Creating a dictionary in racket - list

Write the function build-author-index that consumes a(listof Book) and a list of unique authors (Strings). The function produces an AuthorIndex where the keys are the authors consumed (in the same order) and the values are the titles of all books by that author in the list of Book (also in the same order).
The following is my code. I have to use Beginning Student with List Abbreviations. I am only allowed to use cons, first, second, third, rest, empty?, eq? cons?, list, member?, and length.
posting an image of my code since stack overflow does not allow me to

#lang racket
(define my-bookshelf
'((book-name-1 author-1)
(book-name-2 author-2)
(book-name-3 author-3)
(book-name-4 author-4)
(book-name-5 author-5)))
(define (bookname-of-given-author bookshelf author)
(cond
[(empty? bookshelf)
(error "no this author")]
[(equal? author (second (first bookshelf)))
(first (first bookshelf))]
[else
(bookname-of-given-author (rest bookshelf) author)]))
;;; Test
(bookname-of-given-author my-bookshelf 'author-1)
(bookname-of-given-author my-bookshelf 'author-4)
(define (build-author-index bookshelf author-ls)
(cond
[(empty? author-ls) empty]
[else
(cons (bookname-of-given-author my-bookshelf (first author-ls))
(build-author-index (rest bookshelf) (rest author-ls)))]))
;;; Test
(build-author-index my-bookshelf '(author-1 author-4))
(build-author-index my-bookshelf '(author-4 author-3 author-2 author-1))

Related

In Racket how do i find the length of a list using struct instead of just using only higher-order functions or recursion

I'm pretty bad at understanding data structures in Racket right now so I'm currently working on a question where all I have to do is find the length of the list.
I understand there are many ways to find the length of a list using recursion and foldr and map but I'm trying to find the length of a list a specific way right now.
Here are the details of the question;
For this question, use the following data definition:
(define-struct ls (first rest))
;; a Ls is either
;; '(), or
;; (make-ls first rest) where first is an Int and rest is a Ls.
Keep in mind that since the structure is named ls, and its fields are named first and rest,you will access these fields using ls-first and ls-rest.
Here is the question
Length. Write a function (ls-length L) that consumes a Ls and returns the number of values in it.
For example, (check-expect (ls-length (make-ls 5 (make-ls 7 (make-ls 11 '())))) 3)
Here's a common way to find the length
(define (length lst)
(cond
[(empty? lst) 0]
[(cons? lst) (+ 1 (length (rest lst)))]))
I however want the question solved using
(define-struct ls (first rest))
This is what I have so far but I know that this code seems very wrong, I feel my base case should be correct though.
(define (ls-length L)
(cond
[(empty? L) 0]
[(cons? (ls-first (first L))) (+ 1 (length (rest (ls-rest))))]))
You have to remember that you can't use cons?, rest and first on the new data structure, only empty?, ls-first and ls-rest are allowed. The conditions are quite simple: the list is either empty or not empty, we don't really need cons?. Also, be careful when calling the recursion, the procedure is called ls-length, not length:
(define (ls-length lst)
(cond
[(empty? lst) 0]
[else (+ 1 (ls-length (ls-rest lst)))]))
Compare the above with the well-known length implementation:
(define (length lst)
(cond
[(empty? lst) 0]
[else (+ 1 (length (rest lst)))]))
You see what happened? we only had to replace length with ls-length, and rest with ls-rest. So simple!

Scheme function to take a list and an atom as parameters and returns index of the first location where atom occurs

I'm very new to Scheme and am working on a problem defined as follows:
Write a scheme function find-loc which takes two parameters, a list lst and an atom atm, and returns the index of the first location where atm occurs in the list.
The location index is 1-relative. If atm does not occur in the list, the function returns n + 1, where n is the length of the list.
what I've got so far is:
(define (find-loc list atm)
(if (not(list? list))
0
(cond
((null? list)
1)
((eq? (car list)atm)
1))
(else (+ (find-loc (cdr list atm) 1) )))
I feel that I'm close but am a bit stuck. My main questions are as follows:
how do I define what the atom is?
why am I getting the following error? "define: expected only one expression for the function body, but found 1 extra part"
An atom is defined by this predicate:
(define (atom? x)
(and (not (null? x))
(not (pair? x))))
The error you're receiving is because the syntax of the if expression is incorrect - it must have two parts after the condition (consequent and alternative), and you wrote three. A few comments:
It's better to use a cond when testing for multiple conditions
Don't name a variable as list, it clashes with a built-in procedure of the same name
Better use equal? for testing equality, it's more general
We should use our new and shiny atom? predicate, as per the requirements - even though the null? check is redundant at this point
This is what I mean:
(define (find-loc lst atm)
(cond ((not (list? lst)) 0)
((null? lst) 1)
((and (atom? (car lst)) (equal? (car lst) atm)) 1)
(else (+ 1 (find-loc (cdr lst) atm)))))

easy scheme question

how can I find a list from given database??
Database:
(10 math phys)
(11 math chem)
(13 bio chem)
(15 geo phys)
I want to implement time which shows the first and second exams in a list.
>(time ’10)
(list ‘math ‘phys)
>(time ’19)
empty
And I want to implement secondExams which returns the time of second exams.
>(secondExams ‘phys)
(list ‘10 ’15)
>(secondExams ‘chem)
(list ’11 ’13)
thank you
First, let's clarify your database format. Make it a list of lists:
(define database
'((10 math phys)
(11 math chem)
(13 bio chem)
(15 geo phys)))
Then time just needs to step through your list recursively, and compare the first element of the sub-list with your target value. If we find no matching value, we'll return the empty list. We'll do this in a helper procedure to match the functionality you're precisely seeking.
(define time-ish
(lambda (target lst)
(cond ((null? lst) lst)
((eq? target (caar lst)) (cdar lst))
(else
(time-ish target (cdr lst))))))
(define (time lookin-for)
(time-ish lookin-for database))
Then we can do something very similar for secondExams. Except we'll recursively build a list of matches this time.
(define exam-helper
(lambda (target lst)
(cond ((null? lst) lst)
((eq? target (third (car lst))) (cons (first (car lst))
(exam-helper target (cdr lst))))
(else
(exam-helper target (cdr lst))))))
(define (secondExams lookin-for)
(exam-helper lookin-for database))
I haven't tested this code, but I'm pretty sure it'll work for you.

Finding element in list in Scheme

i'm very beginner of Scheme and try to figure out how it is functioning; so i want to write a basic code:
first of all i have a definition set: zipcode (ZIPCODE CITY STATE)
(define zipcodes '(
(96774 ookala hawaii)
(90001 losangeles california)
(90263 malibu california)
(10044 newyork newyork)
))
i try to write a function that input is zipcode and return city and state name for example:
>(find '10044)
(list 'newyork 'newyork)
>(find '99999)
empty because there is not zipcode like that.
Thanks a lot...
I'm not allowed to us LET function
Use assoc
> (assoc 90001 zipcodes)
(90001 losangeles california)
> (cdr (assoc 90001 zipcodes))
(losangeles california)
(define filter
(lambda (proc lst)
(cond ((null? lst) '())
((proc (car lst)) (cons (car lst) (filter proc (cdr lst))))
(else
(filter proc (cdr lst))))))
(define find-zip
(lambda (zip lst)
(define match (filter (lambda (item) (= zip (car item))) lst))
(if (null? match)
'()
(cdar match))))
(define (find zip)
(find-zip zip zipcode))
I think that will work for you. Filter will apply its first argument (a procedure) to each item in its second argument, which needs to be a list. The first argument needs to return a boolean value for each item it's passed. Filter will then return a list with all of the items that returned true when the first argument was applied. Otherwise, it returns an empty list.
In this case, each item in the list you're passing is itself a list of 3 items, so it compares the first item in that list with the zip code you're looking for. If it's a match, it returns true. So if the zip code is in the list, it will return the three item sub-list. Then we check to see if we got an empty list, if so, then we return an empty list. Otherwise, we take the cdr of the car to get your desired city and state.
Well so you can basically just filter the list for the zip code, I have sketched some code below (I'd write it differently, except I don't know what you have available outside of what is defined in RnRS).
(define find-zip
(lambda (zip codelist)
(if (empty? codelist) empty
(if (= zip (car (car codelist)) (list (cadr (car codelist)) (caddr (car codelist)))
(find-zip zip (cdr codelist))))))
It would probably be better should you use a let, and I think most implementations have a filter function that let you do this better.

Scheme Compare item or list if it's inside the test list (can be nested)

My Goal is to make the function part? return true if a list or an item is inside the nested list.
But so far I can only get it working with signal item inside a first order list. (not nested list yet)
(define part?
(lambda (item l)
(and (not (null? l))
(or (= item (car l))
(part? item (cdr l))))))
my goal is to have
part? of (A (B)), (((B) A (B)) C) is #f and
part? of (A B), (C (A B) (C)) is #t
Where I should improve on this? How can I make the list to compare with the nested list?
DISCLAIMER: I haven't written scheme regularly in 20 years.
I think you want to think about this problem in terms of the whole lispy/schemey approach which is to establish your conditions.
Given an input, item, you want to find if a list contains that item.
A list may contain an item if the list is not null.
A list contains an item if the car of the list matches the item or if the car of the list contains the item
A list contains an item if the cdr of the list contains the item.
A final question to consider, what is the result of (part? '(a b) '(a b))?
I would write the code like this
(define part? (lambda (item l)
(cond ((null? l) f)
((or (same? item (car l)) (part? item (car l))))
(t (part? item (cdr l)))
)
))
(define same? (lambda (a b) (eq? a b)))
I used the cond structure because it fits well with problems of this sort - it just feels right to break the problem out - notice the null check. I wrote same? as a helper function in case you want to write it yourself. You could just as easily to it this way:
(define same? (lambda (a b)
(cond ((and (atom? a) (atom? b)) (eq? a b))
((and (list? a) (list? b)) (and (same? (car a) (car b)) (same? (cdr a) (cdr b))))
(f f)
)
))
which basically says that two items are the same if they are both atoms and they are eq or they are both lists and the cars are the same and the cdrs are the same, otherwise false.
You can just as easily rewrite same? as this:
(define same? (lambda (a b) (equal? a b)))
The point of doing that is that there is a bottleneck in the code - how to determine if two items are the same. If you break that bottleneck out into its own function, you can replace it with different mechanisms. I know you're not here yet, but you will be at one point: you will also be able to rewrite the code so that the predicate is passed in. Something like this (and more up-to-date scheme programmers, feel free to correct me):
(define part-pred? (lambda (same-pred item l)
(cond ((null? l) f)
((or (same-pred item (car l)) (part? item (car l))))
(t (part? item (cdr l)))
)
))
(define part-eq? (lambda (item l) (part-pred? 'eq? item l)))
(define part-same? (lambda (item l) (part-pred? 'same? item l)))
(define part-equal? (lambda (item l) (part-equal? 'equal? item l)))
This has now abstracted the notion of part to be a function that applies the part structural rules and an equality predicate which is supplied by you. That makes it really easy to change the rules. This will make more sense when you hit mapcar.
The problem with the = function used here is, that it is only defined for numbers. To test arbitrary data for equality, there are the predicates eq?, eqv?, and equal?. These are listed here from most discriminating (eq?, basically something like a pointer comparison) to least discriminating (equal? will consider type and structure). The eqv? predicate is somewhere in between (type-aware for numbers, otherwise like eq? for anything else).
To compare lists, you will usually use equal?.
Edit Details on these predicate can be found in the R6RS.
Your solution is missing the idea, since you're dealing with nested lists you need to check if each item in each list is a list itself, if it is then check if the given list is part of the other or part of the rest of the list if not then you need to check the first items are equal and if the rest of the given list is part of the other.
(define part? item l
(cond (and (list? (car item)) (not (list? (car l))) ...)
(and (not (list? (car item))) (list? (car l)) ...)
(and (not (list? (car item))) (not (list? (car l))) ...)
(and (list? (car item)) (list? (car l))) ...)