Scheme: Trying to find largest element in two lists - scheme

I have 3 functions union, largest, and largest_of_two. Union takes two lists and combines them into one (this function has been tested and works). largest is supposed to return the largest element in a given list but only returns #f whether I call it via largest_of_two or on its own. Any help will be greatly appreciated.
(define (union l1 l2)
(cond (
(null? l1) l2)
((cons (car l1) (union (cdr l1) l2)))
)
)
(define (largest x a_list)
(cond
((null? a_list) x)
((< x (car a_list)) (= x (car a_list)))
(else (largest x (cdr a_list)))
)
)
(define (largest_of_two l1 l2)
(largest (car l1) (cdr (union l1 l2)))
)
(display(largest_of_two '(19 30 13 29 38) '(1 50 5 20 41)))

The fundamental problem is that (= x (car a_list)) is a comparison, but you need to make a recursive call here:
(define (largest x a_list)
(cond ((null? a_list) x)
((< x (car a_list)) ; if x is less than the first element
(largest (car a_list) (cdr a_list))) ; call with first element and cdr
(else
(largest x (cdr a_list)))))
When x is less than the first element of the list, you want to call largest again with the first element and a reduced list as arguments.
Yet, calling largest with two arguments like this seems awkward. If I want to find the largest element of the list (1 6 1 8 0 3) I have to call (largest 1 '(6 1 8 0 3)), which is not ideal. A better approach would be to discard the smaller of the first two elements on each iteration until there is only one element left:
(define (largest xs)
(cond ((null? xs) #f) ; empty input: no largest member
((null? (cdr xs)) ; only one member
(car xs))
((> (car xs) (cadr xs)) ; first member is larger than the second
(largest (cons (car xs) (cddr xs)))) ; keep the first member
(else
(largest (cdr xs))))) ; discard the first member
It doesn't make sense to return a numeric result when the input list is empty, so #fis returned in that case. If the input list contains only a single value, then that value is returned (note that this code does not verify that a list of one element contains a number, so (largest '(z)) --> z).
Otherwise the list contains at least two values. If the first is larger than the second, the first is consed onto the rest of the list with the second removed ((cddr xs)) and largest is called again on the result. Otherwise the first value is not larger than the second, so the first element is discarded ((cdr xs)) and largest is called on that result.
There is another minor issue with the posted definition of union in the conditional form:
((cons (car l1) (union (cdr l1) l2)))
There is only one test expression here. Now, this is legal Scheme because when a selected conditional clause contains only a test expression, the value of the test expression is returned. But this is not idiomatic, and it is hard to read. The posted definition for largest used else in a similar situation, and it should be used here, too. Or, just use an if form:
(define (union xs ys)
(if (null? xs)
ys
(cons (car xs) (union (cdr xs) ys))))
Be consistent; use formatting and line breaks to make code clear. And while we are talking about style, please don't scatter parentheses about haphazardly, and prefer kebab-case (aka lisp-case) to snake_case for identifiers in lisps.
With the new definition for largest, largest-of-two has a simpler definition:
(define (largest-of-two xs ys)
(largest (union xs ys)))
> (largest-of-two '(1 4 2 6 3 11 6 -2) '(3 8 -3 7 10 4))
11

Filtering is often called reduce in Scheme and functional languages. It is already explained in detail here. I quote the implementation:
(define (reduce fn list init)
(if (null? list) init
(fn (car list)
(reduce fn (cdr list) init))))
This is a very general function, which takes the operation, the list to operate on and an accumulator, which holds the value of each step.
You just need to implement your maximum function for two arguments.
(define (max a b)
(if (> a b)
a
b))
And then you can pass it to reduce. You just need to add an initial value.
(reduce max '(19 30 13 29 38) 0)
In your case it might be better to split your input list, because all elements can be negative.
(let ((lst '(19 30 13 29 38)))
(reduce max (cdr lst) (car lst)))
If you want to do anything twice or for even more arguments, just use map.
(map (lambda (lst)
(reduce max (cdr lst) (car lst)))
'((19 30 13 29 38)
(1 50 5 20 41)))
The following puts everything in one function.
(define (largest-of . lists)
(define (reduce fn list init)
(if (null? list) init
(fn (car list)
(reduce fn (cdr list) init))))
(define (max a b)
(if (> a b)
a
b))
(map (lambda (lst)
(reduce max (cdr lst) (car lst)))
lists))
(largest-of '(19 30 13 29 38) '(1 50 5 20 41)) ;; => (38 50)
This works also for more than two lists. It is just limited by the maximum number of arguments of your Scheme implementation.
And it works for just one argument.
(largest-of (largest-of '(19 30 13 29 38) '(1 50 5 20 41))) ;; => (50)
You just need to unbox the value with car.

Related

Nested List Issue in Lisp

So I have to write a method that takes in a list like (nested '(4 5 2 8)) and returns (4 (5 () 2) 8).
I figured I needed to write 3 supporting methods to accomplish this. The first gets the size of the list:
(define (sizeList L)
(if (null? L) 0
(+ 1 (sizeList (cdr L)))))
input : (sizeList '(1 2 3 4 5 6 7))
output: 7
The second drops elements from the list:
(define (drop n L)
(if (= (- n 1) 0) L
(drop (- n 1) (cdr L))))
input : (drop 5 '(1 2 3 4 5 6 7))
output: (5 6 7)
The third removes the last element of a list:
(define (remLast E)
(if (null? (cdr E)) '()
(cons (car E) (remLast (cdr E)))))
input : (remLast '(1 2 3 4 5 6 7))
output: (1 2 3 4 5 6)
For the nested method I think I need to do the car of the first element, then recurse with the drop, and then remove the last element but for the life of me I can't figure out how to do it or maybe Im just continually messing up the parenthesis? Any ideas?
Various recursive solutions are possible, but the problem is that the more intuitive ones have a very bad performance, since they have a cost that depends on the square of the size of the input list.
Consider for instance this simple solution:
; return a copy of list l without the last element
(define (butlast l)
(cond ((null? l) '())
((null? (cdr l)) '())
(else (cons (car l) (butlast (cdr l))))))
; return the last element of list l
(define (last l)
(cond ((null? l) '())
((null? (cdr l)) (car l))
(else (last (cdr l)))))
; nest a linear list
(define (nested l)
(cond ((null? l) '())
((null? (cdr l)) l)
(else (list (car l) (nested (butlast (cdr l))) (last l)))))
At each recursive call of nested, there is a call to butlast and a call to last: this means that for each element in the first half of the list we must scan twice the list, and this requires a number of operations of order O(n2).
Is it possible to find a recursive solution with a number of operations that grows only linearly with the size of the list? The answer is yes, and the key to this solution is to reverse the list, and work in parallel on both the list and its reverse, through an auxiliary function that gets one element from both the lists and recurs on their cdr, and using at the same time a counter to stop the processing when the first halves of both lists have been considered. Here is a possible implementation of this algorithm:
(define (nested l)
(define (aux l lr n)
(cond ((= n 0) '())
((= n 1) (list (car l)))
(else (list (car l) (aux (cdr l) (cdr lr) (- n 2)) (car lr)))))
(aux l (reverse l) (length l)))
Note that the parameter n starts from (length l) and is decreased by 2 at each recursion: this allows to manage both the cases of a list with an even or odd number of elements. reverse is the primitive function that reverses a list, but if you cannot use this primitive function you can implement it with a recursive algorithm in the following way:
(define (reverse l)
(define (aux first-list second-list)
(if (null? first-list)
second-list
(aux (cdr first-list) (cons (car first-list) second-list))))
(aux l '()))

Scheme return a list with first half of its elements

Write a procedure (first-half lst) that returns a list with the first half of its elements. If the length of the given list is odd, the returned list should have (length - 1) / 2 elements.
I am given these program as a example and as I am new to Scheme I need your help in solving this problem.
(define list-head
(lambda (lst k)
(if (= k 0)
'()
(cons (car lst)(list-head (cdr lst)(- k 1)))))))
(list-head '(0 1 2 3 4) 3)
; list the first 3 element in the list (list 0 1 2)
Also the expected output for the program I want is :
(first-half '(43 23 14 5 9 57 0 125))
(43 23 14 5)
This is pretty simple to implement in terms of existing procedures, check your interpreter's documentation for the availability of the take procedure:
(define (first-half lst)
(take lst (quotient (length lst) 2)))
Apart from that, the code provided in the question is basically reinventing take, and it looks correct. The only detail left to implement would be, how to obtain the half of the lists' length? same as above, just use the quotient procedure:
(define (first-half lst)
(list-head lst (quotient (length lst) 2)))
It looks like you are learning about recursion? One recursive approach is to walk the list with a 'slow' and 'fast' pointer; when the fast pointer reaches the end you are done; use the slow pointer to grow the result. Like this:
(define (half list)
(let halving ((rslt '()) (slow list) (fast list))
(if (or (null? fast) (null? (cdr fast)))
(reverse rslt)
(halving (cons (car slow) rslt)
(cdr slow)
(cdr (cdr fast))))))
Another way to approach it is to have a function that divides the list at a specific index, and then a wrapper to calculate floor(length/2):
(define (cleave_at n a)
(cond
((null? a) '())
((zero? n) (list '() a))
(#t
((lambda (x)
(cons (cons (car a) (car x)) (cdr x)))
(cleave_at (- n 1) (cdr a))))))
(define (first-half a)
(car (cleave_at (floor (/ (length a) 2)) a)))

Compare elements in the list

I need compare every second element in the list but I don't know how. Here is an example:
(compare? '(1 x 2 x 3 x 4)) -> #t
(compare? '(1 x 2 x 3 o)) -> #f
I can only compare second and fourth element:
(define compare?
(lambda (list)
(equal? (cadr list) (cadddr list))))
I need 6th, 8th, 10th etc.... I don't know length of the list. Please, help me.
Try this answer, filling-in the blanks:
(define (compare? lst)
(if <???> ; if the list has at most two elements
#t ; then return true
(let ((elt (cadr lst))) ; grab the first element to be compared
(let loop ((lst (cddr lst))) ; step on the second group of elements
(cond (<???> #t) ; if there's only one or zero elements left
(<???> #f) ; if the second element is not equal to `elt`
(else (loop (cddr lst)))))))) ; otherwise continue iterating
Let's look at the example of (compare? '(1 x 2 x 3 x 4)).
You want to ensure that (compare? '(2 x 3 x 4)) is true, and that the 1 x before that also matches.
That then means that you want to ensure that (compare? '(3 x 4)) is true (which it is, by definition), and that the 2 x before that also matches.
Notice how we are working with smaller and smaller lists each time. We can do that because lists have structural induction. Because of structural induction, you don't actually have to know the length of the list. The algorithm just works on smaller and smaller sublists until it hits a base case.
Sample skeletal solution (fill in the <???> with suitable code):
(define (compare? lst)
(if (or (null? lst) (null? (cdr lst)))
#t
(let ((item (cadr lst))
(next (compare? (cddr lst))))
(case next
((#f) <???>)
((#t) <???>)
(else (and <???> <???>))))))
(Technically the #f clause is not necessary, but, it may make it clearer to you what the solution approach should be.)
This solution will only work correctly if the matched slots in the list are not #t or #f. Since you're using symbols in your example, it will work correctly.

implement expand function with racket

I can't seem to figure out how to write this function. What I am trying to write is a function expand that takes a list lst as a parameter of the form '(a (2 b) (3 c)) and is evaluated to '(a b b c c c)
This looks like homework, so I'm not giving you a straight answer. Instead, I'll give you some pointers in the right direction. The most useful hint, is that you should split the problem in two procedures, one for processing the "outer" list and the other for generating the repetitions encoded in the inner sublists.
Notice that both procedures are mutually recursive (e.g., they call each other). The expand procedure recurs over the list, whereas the repeat procedure recurs over the number of repetitions. This is the general structure of the proposed solution, fill-in the blanks:
; input: lst - list to be processed
; output: list in the format requested
(define (expand lst)
(cond ((null? lst) ; if the list is null
'()) ; then return null
((not (pair? (car lst))) ; if the first element of the list is an atom
(cons <???> <???>)) ; cons the atom and advance the recursion
(else ; if the first element of the list is a list
<???>))) ; call `repeat` with the right params
; input: n - number of repetitions for the first element in the list
; lst - list, its first element is of the form (number atom)
; output: n repetitions of the atom in the first element of lst
(define (repeat n lst)
(if (zero? n) ; if the number of repetitions is zero
(expand (cdr lst)) ; continue with expand's recursion
(cons <???> ; else cons the atom in the first element and
<???>))) ; advance the recursion with one less repetition
As this was answered three years ago, I don't think that I am helping with homework. Would just like to point out that the two functions really don't need to be mutually recursive. As replicate is a fairly common function, I would propose:
(define (replicate what n)
(if (zero? n)
(list)
(cons what (replicate what (- n 1)))))
(define (my-expand xs)
(if (empty? xs)
(list)
(let ((x (first xs)))
(if (list? x)
(let ((the-number (first x))
(the-symbol (cadr x)))
(flatten (cons (replicate the-symbol the-number)
(my-expand (rest xs)))))
(cons x (my-expand (rest xs)))))))
Of course it is better to use two lists and perform the flatten at the end, something like this:
(define (my-expand xs)
(define (inner-expander xs ys)
(if (empty? xs) (flatten (reverse ys))
(let ((x (first xs)))
(if (list? x)
(let ((the-number (first x))
(the-symbol (cadr x)))
(inner-expander (rest xs) (cons (replicate the-symbol the-number) ys)))
(inner-expander (rest xs) (cons x ys))))))
(inner-expander xs (list)))

Finding the overall average of nested lists in Scheme?

Hey guys, I'm using MIT Scheme and trying to write a procedure to find the average of all the numbers in a bunch of nested lists, for example:
(average-lists (list 1 2 (list 3 (list 4 5)) 6)))
Should return 3.5. I've played with the following code for days, and right now I've got it returning the sum, but not the average. Also, it is important that the values of the inner-most lists are calculated first, so no extracting all values and simply averaging them.
Here's what I have so far:
(define (average-lists data)
(if (null? data)
0.0
(if (list? (car data))
(+ (average-lists (car data)) (average-lists (cdr data)))
(+ (car data) (average-lists (cdr data))))))
I've tried this approach, as well as trying to use map to map a lambda function to it recursively, and a few others, but I just can't find one. I think I'm making thing harder than it should be.
I wrote the following in an effort to pursue some other paths as well, which you may find useful:
(define (list-num? x) ;Checks to see if list only contains numbers
(= (length (filter number? x)) (length x)))
(define (list-avg x) ;Returns the average of a list of numbers
(/ (accumulate + 0 x) (length x)))
Your help is really appreciated! This problem has been a nightmare for me. :)
Unless the parameters require otherwise, you'll want to define a helper procedure that can calculate both the sum and the count of how many items are in each list. Once you can average a single list, it's easy to adapt it to nested lists by checking to see if the car is a list.
This method will get you the average in one pass over the list, rather than the two or more passes that solutions that flatten the list or do the count and the sums in two separate passes. You would have to get the sum and counts separately from the sublists to get the overall average, though (re. zinglon's comment below).
Edit:
One way to get both the sum and the count back is to pass it back in a pair:
(define sum-and-count ; returns (sum . count)
(lambda (ls)
(if (null? ls)
(cons 0 0)
(let ((r (sum-and-count (cdr ls))))
(cons (+ (car ls) (car r))
(add1 (cdr r)))))))
That procedure gets the sum and number of elements of a list. Do what you did to your own average-lists to it to get it to examine deeply-nested lists. Then you can get the average by doing (/ (car result) (cdr result)).
Or, you can write separate deep-sum and deep-count procedures, and then do (/ (deep-sum ls) (deep-count ls)), but that requires two passes over the list.
(define (flatten mylist)
(cond ((null? mylist) '())
((list? (car mylist)) (append (flatten (car mylist)) (flatten (cdr mylist))))
(else (cons (car mylist) (flatten (cdr mylist))))))
(define (myavg mylist)
(let ((flatlist (flatten mylist)))
(/ (apply + flatlist) (length flatlist))))
The first function flattens the list. That is, it converts '(1 2 (3 (4 5)) 6) to '(1 2 3 4 5 6)
Then its just a matter of applying + to the flat list and doing the average.
Reference for the first function:
http://www.dreamincode.net/code/snippet3229.htm

Resources