Searching a defined list in Scheme - list

I have this list
(define masterList(list redApple chickenLeg porkLoin milkD baguetteBread orangeJuice beanCan))
I am trying to make a function called lookup that will take an integer and return the element from the list that matches that integer. The list contains elements from a structure in this format
(define-struct storeItem (id des cost))
So I will be passing an integer that represents id and I want storeItem to be retuned.
For instance -
(define redApple (make-storeItem 0 "red delicious apple" 1.99))
If I searched masterList and passed it 0, I would expect redApple to be returned.
Any help on the syntax?
(define (contains masterList x)
(cond
((null? masterList) #f)
((eq? (car masterList) x) #t)
(else (contains (cdr masterList) x))))
This is what I am trying to make work.
It returns true/false correctly based on what I pass it.
(contains materList redApple) returns true.
How can I modify this to return redApple if 0 is entered?
;; These are the constructors to make the elements in our structure
(define redApple (make-storeItem 0 "red delicious apple" 1.99))
(define chickenLeg (make-storeItem 1 "boned chicken" 2.99))
(define porkLoin (make-storeItem 2 "processed pork" 4.99))
(define milkD (make-storeItem 3 "vitamin d milk" 3.99))
(define baguetteBread (make-storeItem 4 "french bread" 0.99))
(define orangeJuice (make-storeItem 5 "fruit juice drink)" 1.49))
(define beanCan (make-storeItem 6 "beans in a can" 2.49)
;; Creating a list that we will use as our master list which contains elements from our structure
(define masterList(list redApple chickenLeg porkLoin milkD baguetteBread orangeJuice beanCan))

Your general structure is correct, but you're not testing the correct condition with
(eq? (car masterList) x)
You don't want to compare x with the whole element of the list, just with its id component. So that should be:
(= (storeItem-id (car masterList)) x)
Also, to compare numbers you should use = or eqv? rather than eq?. See What is the difference between eq?, eqv?, equal?, and = in Scheme?
If you want to get the object with the ID, rather than just #true or #false, return (car masterList) when the ID matches.
(define (find-storeItem masterList x)
(cond ((null masterList) #false)
((= (storeItem-id (car masterList)) x) (car masterList))
(else (find-storeItem (cdr masterList) x))))

Related

Racket: Check if there is a list in a list

this is my first question here! :)
I need a function that checks if there is a list inside a list. It should give false when there is a list inside a list. I tried simple things like:
(define (list-inside-list? ls)
(if (or (list? (first ls)) (list? (rest ls))) false true))
I probably need lambda but I just don't know how?
Would appreciate a lot for help!
There is no list inside the empty list.
Otherwise, there is a list inside a list if
its first element is a list,
or if there is a list inside the rest of the list.
The trick is then to turn this into code, thinking particularly hard about how to express the last case: to do it you might want to write a function which determines if there is a list inside a list ... well, what's the function you're writing do?
a warm welcome to StackOverflow.
I haven't heavily tested, but maybe this approache helps you:
(check-expect (contains-no-sublist? (list )) #true)
(check-expect (contains-no-sublist? (list "red" "green" "blue")) #true)
(check-expect (contains-no-sublist? (list (list "light red" "dark red") "green" "blue")) #false)
;; contains-no-sublist? checks if any element in the list is a list itself and returns #false, if it finds a list in the list (nested list).
(define contains-no-sublist? ;; define a function with the name "contains-no-sublist?"
(lambda [L] ;; define the function as a lambda expression over a given input list L
(cond ;; the function returns either #t or #f
[(empty? L) #true] ;; an empty list doesn't contain a sublist, so #t = #true can be returned
[(cons? L) ;; else still a list is given
(cond
[(list? (first L)) #false] ;; either the first element of the list is a list itself, then return false.
[else (contains-no-sublist? (rest L))] ;; or the first element is not a list itself, then check for the rest of the list if it contains any sublist
)
]
)
)
)
use cond
#lang racket
(define (no-list-inside?-by-cond ls)
(cond
[(empty? ls) #t]
[(list? (first ls))
#f]
[else
(no-list-inside?-by-cond (rest ls))]))
;;; TEST
(no-list-inside?-by-cond '(1 2 3)) ; should be #t
(no-list-inside?-by-cond '(1 2 3 '(3) 4)) ; should be #f
(no-list-inside?-by-cond '(1 2 3 '() 5)) ; should be #f
use andmap
#lang racket
(define (no-list-inside?-by-andmap ls)
(andmap (lambda (x) (not (list? x))) ls))
;;; TEST
(no-list-inside?-by-andmap '(1 2 3 2)) ; should be #t
(no-list-inside?-by-andmap '(1 2 3 '(3) 4)) ; should be #f
(no-list-inside?-by-andmap '(1 2 3 '() 5)) ; should be #f
use filter
#lang racket
(define (no-list-inside?-by-filter lst)
(empty? (filter list? lst)))
;;; TEST
(no-list-inside?-by-filter '(1 2 3)) ; should be #t
(no-list-inside?-by-filter '(1 2 3 '(3) 4)) ; should be #f
(no-list-inside?-by-filter '(1 2 3 '() 5)) ; should be #f

Scheme - Sorting a List of Lists

So, I'm working on sorting in Scheme (MIT Scheme). I've figured out how to sort a basic list of integers, however I can't quite seem to figure out how to sort a list of lists. Here's the code for sorting a list of integers via selection sort:
(define sortdata
(lambda (lst min)
(cond ((null? lst) min) ;null list, return current
((< (car lst) min) (sortdata (cdr lst) (car lst))) ;compare with head of list
(else (sortdata (cdr lst) min))
)
)
)
I'm not very well versed in scheme as I've just started using it. Rather than sort a list like this one: ( 4 8 9 2 6 15 3), I'm trying to sort a lists of lists, but only by one field the sublist (the age in this case). Such as this: (("bob" 17)("mary" 14)) [Assume the first field is the name, and second is the age.]
EDIT: And as such, the sorted list would then look like this: (("mary" 14)("bob" 17))
Much thanks to anyone who can help or point me to a good reference!
Introduction
The basic elements of a search are:
Table: a collection of records
Record: a collection of fields
Field: a value of interest.
Make a language for your records
(define name car)
(define grade cadr)
;; record record -> record
(define (return-record-with-greater-name record1 record2)
(if (name>? record1 record2)
record1
record2))
(define name>?
(make-record-compare-function string> name))
Make a language for comparing records
;;; This is a partial implementation
;; [any? any? -> boolean] [listof any? -> any?] -> [listof any? -> any?]
(define (make-record-compare-function predicate field)
(lambda (record1 record2)
(predicate (field record1) (field record2))))
Make a language for searching tables
;;; This is a partial implementation
;; [any? any? -> any?] -> [listof any? -> any?]
(define (make-table-search comparator)
(define (inner table best-match)
(if (null? table)
best-match
(inner (cdr table)
(comparator best-match
(car table)))))
(lambda (table)
(inner (cdr table)
(car table))))
Usage
racket> (define record1 (list "mary" 14))
racket> (define record3 (list "Ben" -42))
racket> (define record2 (list "bob" 17))
racket> (define sort-by-name
(make-table-search return-record-with-greater-name))
racket> (sort-by-name (list record3 record1 record2))
'("mary" 14)
Since you are using a comparative sorting algorithm it would be fairly easy to sort other things than integers. Basically, what you need to do is parametrize your comparator. In your current example this is the function <, however this can be anything!
Note Your code does not work but you are almost there. So I will leave it as is and just show you how you could do it.
(define sortdata
(lambda (lst min comparer)
(cond ((null? lst) min) ;null list, return current
((comparer (car lst) min) (sortdata (cdr lst) (car lst))) ;compare with head of list
(else (sortdata (cdr lst) min)))))
In this case your comparar could be:
(lambda (x y) (> (cadr x) (cadr y)))
This lambda will take the age of each person (cadr) and compare them with eachother.
Hope this helps!

Finding the occurence element in the list in racket

Assume (list "apple" "orange" "apple" "grape" "orange")and produce (list (list 2 "apple") (list 2 "orange") (list 1 "grape")).
The most common fruit will occur first in the produced list.
In the case of ties, order the tied pairs with the fruit in increasing alphabetical order.
use abstract list function such as map,filter, foldr and quicksort in local. no recursion.
i'm not sure how to do it without recursion.
i wrote like this:
(define (function list)
(cond
[(empty? list) empty]
[else
(local
(define (helper1 a b)
(cond
[(equal? a b) a]
[else b]))
(define T (foldr helper1 (first list) (rest list)))
(define (count a)
(cond
[(equal? a T) true]
[else false]))
(define new-list (quicksort (length (filter count list)) >))]
The most efficient way is to use a (mutable) hash table:
(define (count-by-type lst)
; create hash
(define h (make-hash))
; update hash, creating entries if needed, otherwise adding 1 to existing entry
(map (lambda (e) (hash-update! h e add1 0)) lst)
; create list of (count key) elements from hash and sort accordingly
(sort (map (lambda (e) (list (cdr e) (car e))) (hash->list h))
(lambda (x y) (or (> (car x) (car y))
(and (= (car x) (car y)) (string<? (cadr x) (cadr y)))))))
testing:
> (count-by-type (list "apple" "orange" "apple" "grape" "orange"))
'((2 "apple") (2 "orange") (1 "grape"))
I just rehashed my own answer from a previous question. This seems to be a similar assignment, but without struct
Using a hash you could do it with only one pass through the unsorted list, then produced a list that then was sorted with a special <-function that sorts by count, then fruit.
These hints are for a functional solution. First sort the argument (sort list-of-fruits string>?). that the in descending order and oposite of your result. .
Given the list has at least one element:
(let rec ((cur (car sorted-fruits)) (cnt 1) (lst (cdr sorted-fruits)) (acc '()))
(cond ((equal? cur (car lst)) (rec cur (add1 cnt) (cdr lst) acc))
(else (rec (car lst) 1 (cdr lst) (cons (list cnt cur) acc)))))
This will produce a list in ascending order with counts.
If you sort again:
(sort list-of-counts-and-fruit (lambda (x y) (>= (car x) (car y)))
sort in Racket is stable. That means if you have two with equal counts in the list they will end up in their original order. The original order was the ascending animal order so the result is ordered by count descending, then name ascending.
I guess your procedure can be made by chaining these together, perhaps using let to store intermediates to make expressions shorter and more readable.

Recursively creating list in scheme

I come up again with my strange Scheme questions.
I have a definition that remove subelement(based on search occurrence) from a list and generate new list without it (based on this answer here).
(func '1 mylist) ; will return mylist without all sublists containing 1
All was working fine until I realized that I need to repeat my definition for each element in another list.
I call it recursively, but with every call I use the original list not the previous filtered.
Or with another words I want to achieve this:
(define filterList '(1 2 3))
(func '3 (func '2 (func '1 mylist) ); list without all sublists containig 1 2 3
I'm tottaly stuck. Thanks everyone for the help.
This is a basic loop over the lists of elements (elts) to remove from the initial list (lst):
(define (func2 elts lst)
(if (null? elts)
lst
(func2 (cdr elts) (func (car elts) lst))))
then
(func2 '(1 3) '(1 2 3))
=> '(2)
or, in Racket:
(define (func2 elts lst)
(for/fold ((res lst)) ((e (in-list elts)))
(func e res)))

Scheme: adding 2 lists by index

I need to write a function in Scheme (Racket) that takes two not necessarily equal
length lists and return a list which each element is the sum of the elements of the same
index from the two lists. if the lists' length is not equal the shorter one should append to itself until it reaches the size of the longer one. for example:
=> (addLists '(1 2 3 4) '(1 2))
(2 4 4 6)
=> (addLists '(1 2 3 4) '(1 2 3 4 5))
(2 4 6 8 6)
Until now I was able to write a function that completes this for equal length lists, but the problem lies with how do I increase the length of the shorter list within this function (or with a helper function that gets a list and a size and extends it properly).
(define (sumListPairs lst1 lst2)
(if (null? lst1) null
(cons (+ (car lst1) (car lst2))
(sumListPairs (cdr lst1) (cdr lst2)))))
Will appreciate any help, Thank you.
This can be done, but since I have the impression that this is a homework exercise, I'll only give a hint. First, introduce a named-let to do the actual recursion. Then, expand the number of cases in the recursion from two to four.
(define (sumListPairs lst1 lst2)
(let loop ((l1 lst1) (l2 lst2))
(cond ((and (null? l1) (null? l2)) null)
((null? l1) ...)
((null? l2) ...)
(else (cons (+ (car lst1) (car lst2))
(loop (cdr l1) (cdr l2)))))))
Now, fill in the ... parts. Note that you have access to all of l1, l2, lst1 and lst2. (You might want to refactor a bit after you're done, since the cases will be quite similar.)