Scheme: Using objects to modify lists - list

I'm trying to return the max element in a list using objects. I want to try and find a way to do so without simply getting the maximum element of the list, and instead I'm trying to check the first two elements against each other to get the max, and then check the max of the first two elements against the next element and so on.
Here's what I currently have:
(define (stat-set)
(let ((L '(10 2 5)))
(define (largest)
(define (current-max)
(begin
(set! current-max
(max (car L) (cadr L)))
current-max))
(current-max))
(lambda (method)
(cond ((eq? method 'largest) largest)))))
(define n (stat-set))
(n 'largest))
I'm pretty sure it's a problem with the line
(max (car L) (cadr L)))
but I'm not sure how to fix it. When I try using largest on a list of '(2 10), it returns 10. However, if I were to use largest on a list of '(5 2 10) it returns 5, while I would like it to return 10 still. I know this is because I'm only comparing the first two elements by using car and cadr, but am unsure as to how to store the maximum of '(2 10) so I can compare it to '(5).
Any help would be appreciated. Thanks.

Related

Racket call function on each element of list

I am trying to write a function that takes a list of divisors, a list of numbers to test and applies drop-divisible for each element of the list of divisors. I am supposed to use filter, map or foldl and no recursion
I wrote the drop-divisible function:
(define (drop-divisible l n)
(cond
[(empty? l) empty]
[(empty? (rest l)) l]
(let ([i (first l)])
(if (zero? (modulo i n))
(drop-divisible (rest l) n)
(cons i (drop-divisible(rest l)n))))]))
That seems to work, but I'm confused on how I can call drop-divisible for each element in the list when it only wants one list and an integer as a parameter?
Hopefully, that makes sense, thanks
When you want "all the elements of this list except the ones that meet such-and-such criterion", the filter function provides an easy way to do that:
(define (drop-divisible l n)
(filter (λ (i) (not (zero? (modulo i n))))
l))
> (drop-divisible '(4 6 9 8 12 14) 3)
'(4 8 14)
filter constructs a new list, containing only the items of the original list that meet your criterion. The first argument to filter is a function that takes a single element of the list and returns #f if the element should be skipped when creating the new list, and returns any other value to include the element in the new list. The second argument to filter is the list to filter.
In other words, filter does exactly what your code does, but it's generalized to apply any filtering criterion.

get the elements from a nested list in LISP

I am trying to figure out how to access the elements in a nested list in LISP. For example:
((3 (1 7) (((5)))) 4)
If I use dolist, i run into the brackets. Is there any method to just get the elements from the list?
This is actually a surprisingly subtle question! It's in some ways the equivalent of asking: how do I get the nested elements of an HTML DOM, by specifying a pattern. (more on that aspect later)
If you just want to get the non-list elements as a sequence, e.g.
((3 (1 7) (((5)))) 4) -->
(nth 3 (3 1 7 5 4)) -->
5
You can use the 'cheat' way: the flatten function in the CL alexandria library. (via quicklisp)
(ql:quicklisp :alexandria)
(nth 3 (alexandria:flatten '((3 (1 7) (((5)))) 4)))
Which gives us the sought after,
5
But, the alexandrian function is simple enough that we can take a look at the source code itself:
(defun flatten (list)
(cond
((null list)
nil)
((consp (car list))
(nconc (flatten (car list)) (flatten (cdr list))))
((null (cdr list))
(cons (car list) nil))
(t
(cons (car list) (flatten (cdr list))))))
As you can see, it's a recursive function -- at each level of recursion it asks the question: what is the object that I'm flattening? If it's the empty list, return nil. I'm done!
Otherwise it has to be a non empty list. If the first element of the list is also a list then flatten that and also flatten the cdr of the function argument list and concatenate the results.
If the first element is not a list and the second element is '(), that must mean we have a list with one element: return it.
The final case case, which exhausts our possibilities is that the first element in the list is an atom while the rest of the list is a list with at least one element. In that case concatenate the first element with the results of a flatten performed on the rest of the list.
The fact that the description in English is so ponderous shows the power of recursion, (and also my own lack of fluency when describing it).
But there's actually another way your question could interpreted: if I have a list that looks something like: ((n1 (n2 n3) (((n4)))) n5) How do I get at n2, even if n2 is itself a list? Our previous recursive algorithm won't work -- it depends on n2 not being a list to know when to stop. But, we can still use recursion and the very list we're searching as the basis for a pattern:
;; For each element in our pattern list look for a corresponding
;; element in the target, recursing on lists and skipping atoms that
;; don't match.
(defun extract-from-list (pattern target to-find)
(dotimes (i (length pattern))
(let ((ith-pattern (nth i pattern)))
(cond
((consp ith-pattern)
(let ((results
(extract-from-list (nth i pattern)
(nth i target)
to-find)))
(when results
(return results))))
(t
(if (eq to-find ith-pattern)
(return (nth i target))))))))
Note that,
(extract-from-list
'((n1 (n2 n3) (((n4)))) n5) ;; The pattern describing the list.
'((3 (1 7) (((5)))) 4) ;; The list itself.
'n4) ;; which of the elements we want.
still returns the old answer:
5
But,
(extract-from-list
'((n1 (n2 n3) (n4)) n5) ;; The pattern describing the list, note (n4) rather than (((n4)))
'((3 (1 7) (((5)))) 4) ;; The list itself.
'n4) ;; The element we want to pull from the list
Returns
((5))
Magic! One of the aspects of Lisp that makes it so extraordinarily powerful.

Scheme - Recursion : Sum consecutive elements of a list

I'm trying to write a function using Scheme that :
take a list of integers with more than two elements as a parameter
sum the n-th-element and (n+1)-th-element
return this list
Result should be as follows :
> (SumNeighbors (list 1 2 3 4))
(3 5 7)
I think I get the way to add elements but my recursion is totally wrong...
(define (SumNeighbors lst)
(if (not (null? (cdr lst)))
(append (list (+ (car lst) (car (cdr lst)))) (SumNeighbors (cdr lst)))))
Any help would be appreciated.
The solution to this problem follows a well-known pattern. I'll give you some hints, it'll be more fun if you find the answer by your own means:
(define (SumNeighbors lst)
(if <???> ; if there's only one element left
<???> ; we're done, return the empty list
(cons ; otherwise call `cons`
(+ <???> <???>) ; add first and second elements
(SumNeighbors <???>)))) ; and advance recursion
Notice the following:
Your solution is lacking the base case - what happens when the list we're traversing only has one element left? it's time to finish the recursion! and because we're building a list as the output, what should be the value returned?
We normally use cons to build an output list, not append. That's the natural way to build a list
The part of this procedure that falls outside the solution template is the fact that we stop when there's a single elment left in the list, not when the list is empty (as is the usual case)
You'll see that many procedures that iterate over an input list and return a list as output follow the same solution template, it's very important that you learn how and why this works, it's the foundation for writing solutions to other similar problems.
#!r6rs
(import (except (rnrs base) map)
(only (srfi :1) map))
(define (sum-neighbors lst)
(map + lst (cdr lst)))
The higher order function map as defined in SRFI-1 supports uneven lenght arguments. It will stop at the shortest list.
If you call (sum-neighbors '(1 2 3 4)) it will become (map + (1 2 3 4) (2 3 4)) which is the same as (cons (+ 1 2) (cons (+ 2 3) (cons (+ 3 4) '())))

Creating a list of lists of repeating elements

this is a homework problem I'm stuck on. I have to create a function in Racket without using explicit recursion or local, that takes in a list of pairs, where the first element of each pair is a non-negative integer, and produces a new list of lists, where each list is k occurrences of the second element in each pair, where k is the first element of each pair. For example (expand-pairs (list (list 1 2) (list 3 4))) would produce (list (list 2) (list 4 4 4))
I got some code working, but only if the second element is a number. Since the question doesn't specify what type of element the second element is, I assume it needs to work for any element. So my function can solve the above example, but can't solve (expand-pairs (list (list 1 'a) (list 3 'b))).
Here is my code:
(define (expand-pairs plst)
(map
(lambda (x)
(map
(lambda (y) (+ (first (rest x)) y))
(build-list (first x) (lambda (z) (- z z)))))
plst))
My main problem is I don't know how to create a list of length k without using recursion or build-list, but then if I use build-list it creates a list of numbers, and I don't know how to convert that to a list of symbols or any other element.
Can anyone point me in the right direction?
Here's another possible implementation, building on #RomanPekar's answer but a bit more idiomatic for Racket:
(define (expand-pairs lst)
(map (lambda (s)
(build-list (first s) (const (second s))))
lst))
It makes use of the higher-order procedures map, const and build-list to create an implementation without using explicit recursion or local. The trick here is to understand how the following expression will return 5 copies of x:
(build-list 5 (const 'x))
^ ^ ^
#copies constant element
=> '(x x x x x)
Something like this:
(define (expand-pairs plst)
(map (lambda(x) (build-list (car x) (lambda(k) (cadr x)))) plst))
You don't have to use k in the build-list, just take second element of pair.

functions and lists in scheme/racket

How would you define a function which takes one argument, which should be a list, and returns the elements in the
list which are themselves lists?
(check-expect (find-sublists ’(1 2 () (3) (a b c) a b c))
’(() (3) (a b c)))
Do you have experience designing functions that can filter through a list?
A simpler problem with the same flavor as the original is something like this: design a function that takes a list of numbers and keeps only the even numbers. Would you be able to do that function?
Looking at http://www.ccs.neu.edu/home/matthias/HtDP2e/htdp2e-part2.html and going through its guided exercises may also help.
Two useful tools which should start you on your way:
1) Traversing through a list:
; traverse: takes a list of numbers
; Goes through each element, one-by-one, and alters it
(define traverse
(lambda (the_list)
(if (empty? the_list)
empty
(cons (+ 1 (first the_list))
(traverse (rest the_list))))))
(traverse (cons 3 (cons 4 empty))) returns (cons 4 (cons 5 empty))
2) list?:
(list? (list 1 2 3)) returns #t
(list? 5) returns #f