Racket call function on each element of list - 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.

Related

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: Using objects to modify lists

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.

New to Racket: why is the if statement affecting the return?

I just started learning Racket so I am still trying to figure out the intricacies of the language. I am trying to implement my own search function in a list. If the function finds it, it returns the index, otherwise it returns -1.
(define (find-index list item)
(if (equal? (length list) 1)
(if (equal? (first list) item) 0 1)
(if (equal? (first list) item)
0
(+ 1 (my-search (rest list) item)))))
So the find-index function is a recursive function that walks through the list looking for an item that is equivalent to "item." I have written it so that, if there are 4 elements in a list, the function can return any number between 0-4.
(define (my-search list item)
(define length (my-length list))
(define index (find-index list item))
(if (= index length) -1 index))
My idea is that if the find-index function returns a number equal to the list's length, it means the function did not find the item, therefore my-search function is supposed to return -1.
However, when I put in
(my-search (list "apple" "barbecue" "child" "demon" "enter") "fire")
the result I get is 3, instead of -1. If I print index before the if statement the index is 3 instead of 5. If
(if (= index length) -1 index))
is not part of the my-search function then everything is fine.
What I think is going on is that index is the id for the function itself, not the result of the function. However, I don't see why that effects the returning result of my-search. Is anyone willing to shed some light on this question?
Also, any style critique is welcome. I would like to know if I am not following conventions.
The weird behavior is caused by the fact that find-index is calling my-search which is calling find-index (a mutual recursion!). At some point, that extra if is causing the recursion to end prematurely. Solution: replace the call to my-search with find-index in the find-index procedure.
Now that that was settled, we can write a single procedure for finding an element's index in a list or signaling that it wasn't found, like this:
(define (find-index lst item)
(cond ((empty? lst) #f)
((equal? (first lst) item) 0)
(else
(let ((result (find-index (rest lst) item)))
(if result (add1 result) #f)))))
Let's see how the above improves your procedure:
The preferred way to structure a procedure with multiple conditions is to use a cond
You should not use list as a parameter name, it clashes with a built-in procedure with the same name
For the same reason, you should not call length a local definition
It's not a good idea to use length for checking if we stepped outside of a list, a well-built recursion will take care of that, without having to iterate over the list all over again
It's common to use #f to indicate that a search procedure didn't find what it was looking for
In a well-structured recursion over lists, you should check if a list is empty, normally this is the first base case we write - your procedure will fail if an empty list is passed
We use let to declare local variables, in this case it makes sense, to avoid calling the recursion twice
Use (add1 x), it's more idiomatic than (+ 1 x)
But wait, we can do better! The above solution can be rewritten in a tail-recursive style; by ensuring that the recursive call is the last thing we do, our procedure will use constant space, and it'll be as efficient as a loop in a conventional programming language. The trick is to pass an extra parameter with the value to return (in this case, the index). I'll use a named let for brevity:
(define (find-index lst item)
(let loop ((lst lst) (idx 0))
(cond ((empty? lst) #f)
((equal? (first lst) item) idx)
(else (loop (rest lst) (add1 idx))))))
You can verify that both procedures work as advertised:
(find-index (list "apple" "barbecue" "child" "demon" "enter") "fire")
=> #f
(find-index (list "apple" "barbecue" "child" "demon" "enter") "child")
=> 2
That's how I would attack the problem.
(define (find-index L item) ; L your list. item the item for which you want the index
(define (aux L res) ; Auxiliary function. L your list. item the item for which you want the index
(cond ((null? L) -1) ; No thing was found, return -1.
((eq? (car L) item) res) ; If the item is equal to the current item then return the position.
(else (aux (cdr L) (add1 res))))) ; Move on to the next item in the list and increment the position.
(aux L 0)) ; Call of the auxiliary function that will be doing the job
Test run...
(define L '(a b c d))
Element not in the list
(find-index L 'e)
Output : -1
Element "d"
(find-index L 'd)
Output : 3
Here is a version of find-index that attempts to use the same style as your original example. Instead of list I use xs (which is short for "list of xes").
Note that it would be better to use the false value #f to indicate "not found".
(define (find-index xs item)
(if (empty? xs)
-1 ; not found
(if (equal? (first xs) item)
0 ; found at beginning
(let ([index-in-rest (find-index (rest xs) item)]) ; index in rest of list
(if (= index-in-rest -1)
-1 ; not found in rest of list
(+ 1 index-in-rest)))))) ; add 1 because we skipped
the first element

Abstract List Functions in Racket/Scheme - Num of element occurrences in list

So I'm currently stuck on a "simple?" function in Racket. It's using the Intermediate Student with lambda language.
Some restrictions on this are that NO recursion is allowed, neither are local functions. It's plain and simple abstract list functions.
What this function is supposed to do is to take in a list of numbers, and output a list of pairs in which each pair has the first element as the number with the second element being the number it has occurred in the list.
Examples:
(1 1 2 3) => ((1 2) (2 1) (3 1))
(2 3 4 3) => ((2 1) (3 2) (4 1))
I have a function that produces the number of occurrences by inputting a list of numbers and a number which is:
(define (occurrences lon n)
(length (filter (lambda (x) (= x n)) lon)))
My approach, which was clearly wrong was:
(define (num-pairs-occurrences lon)
(list (lambda (x) (map (occurrences lon x) (remove x lon)) x))
I thought the above would work, but apparently my lambda isn't placed properly. Any ideas?
It's a bit trickier than you imagine. As you've probably noticed, we must remove duplicate elements in the output list. For this, is better that we define a remove-duplicates helper function (also using abstract list functions) - in fact, this is so common that is a built-in function in Racket, but not available in your current language settings:
(define (remove-duplicates lst)
(foldr (lambda (e acc)
(if (member e acc)
acc
(cons e acc)))
'()
lst))
Now it's easy to compose the solution using abstract list functions:
(define (num-pairs-occurrences lon)
(map (lambda (e) (list e (occurrences lon e)))
(remove-duplicates lon)))
The above might return and output list in a different order, but that's all right. And before you ask: yes, we do need that helper function. Please don't ask for a solution without it...
An easy, self-contained solution would be:
(define (num-pairs-occurences lst)
(foldl (lambda (e r)
(if (or (null? r) (not (= (caar r) e)))
(cons (list e 1) r)
(cons (list e (add1 (cadar r))) (cdr r))))
null
(sort lst >)))
Basically, you sort the list first, and then you fold over it. If the element (e) you get is the same as the first element of the result list (r), you increment the count, otherwise you add a new sublist to r.
If you sort by > (descending), you can actually use foldl which is more memory-efficient. If you sort by < (ascending), you need to use foldr which is less efficient.

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.