I need to return from a list only those values which are odd so I am trying to break my list using car and cdr functions. I have a recursive funciton call that checks if the Car returns a list then further break it using car and cdr , otherwise just pass the first element to a function call check if Odd.
The problem with the special case (10 11 (12 13)) is that
car returns 10
cdr returns (11 (12 13))
then in second iteration
car returns (11 (12 13))
cdr returns (11 (12 13))
so How can i further break my list using car and cdr. I need to preserve the brackets in my final answer as well as only return the list having odd values of integers.
for a function that needs to work on an arbitrary nested list I find it easy to first write the flat list version (filter-odd in our case) and then edit it to produce the nested version (I will call it filter-odd*)
First for normal filter-odd
(define filter-odd
(lambda (ls)
(cond
[(null? ls) '()]
[(odd? (car ls)) (cons (car ls) (filter-odd (cdr ls)))]
[else (filter-odd (cdr ls))])))
Now for filter-odd* (one right-hand side will be left as an exercise (though it seems like you know the answer from your question))
(define filter-odd*
(lambda (ls)
(cond
[(null? ls) '()]
[(list? (car ls)) #| Do something with both car and cdr of ls |# ]
[(odd? (car ls)) (cons (car ls) (filter-odd* (cdr ls)))]
[else (filter-odd* (cdr ls))])))
As a note, this design pattern can be used to help write any recursive program and convert it from only working on flat lists to working on arbitrarily deep lists.
Here's a general solution, for lists with an arbitrary level of nesting:
(define (odds-list lst)
(cond ((null? lst) '()) ; the list is empty
((not (list? (car lst))) ; first element is not a list
(if (odd? (car lst)) ; element is odd
(cons (car lst) (odds-list (cdr lst))) ; build the returned list
(odds-list (cdr lst)))) ; element is even
(else (cons (odds-list (car lst)) ; first element is a list
(odds-list (cdr lst))))))
Notice that three cases need to be considered:
If the list is empty
If the first element of the list is not a list
If the first element of the list is a list
For the second case, two further cases need to be considered:
If the element is odd, then we add it to the list returned
If the element is even, we skip it and continue with the next element
Here's my take:
(define filter*
(lambda (e f)
(cond ((pair? e)
(append (filter* (car e) f)
(filter* (cdr e) f)))
((null? e) '())
((f e) (list e))
(else '()))))
and then you can do:
> (filter* '(1 (2 . 3) ((4 . 5))) even?)
(2 4)
> (filter* '(1 (2 . 3) ((4 . 5))) odd?)
(1 3 5)
Related
I am quite new with Scheme and with StackOverflow as well!
So, for the first contact I would like to do something simple and easy in Scheme.
I want to define a function that substracts the elements of the introduced list.
For example, the inputs should be: (sub '(4 12 6) '(0 6 3))
And the output should be: (4 6 3)
Thanks!!
What you'll need is to have a base case where you check if either list is empty and evaluate it to the empty list or you make a pair with the calculation of the first element of each list and the recursion for the rest of both lists. Basically you end up with:
(cons (- 4 0) (cons (- 12 6) (cons (- 6 3) '()))) ; ==> (4 6 3)
As an example of a recursive list processing function here is one that negates all elements:
(define (negate-list lst)
(if (null? lst)
'()
(cons (- (car lst))
(negate-list (cdr lst)))))
(negate-list '(1 2 3 4)) ; ==> (-1 -2 -3 -4)
Now there are even more fancy ways to do this. Eg,. you can use tail recursion:
(define (negate-list lst)
(let loop ((lst lst) (acc '()))
(if (null? lst)
(reverse acc)
(loop (cdr lst)
(cons (- (car lst)) acc)))))
You can use map:
(define (negate-list lst)
(map - lst))
So there you go. you're half way there.
I defined a function called zip which took two lists as parameters and returned a list of pairs.
(define (zip list1 list2)
(if (null? list1)
'()
(cons (list (cons (car list1) (car list2)))
(zip (cdr list1) (cdr list2)))))
(zip (list 1 3 5) (list 2 4 6))
> (((1 . 2)) ((3 . 4)) ((5 . 6)))
Now I'm basically having trouble writing the inverse function of this. This is what I have so far. This function needs to output a list of two lists. I only attempted at making the first of the two lists to make it easier for myself but the output is not what I want.
(define (unzip u-list)
(if (null? u-list)
'()
(list (car (car (car u-list))) (unzip(cdr u-list)))))
(unzip (zip (list 1 3 5) (list 2 4 6)))
> (1 (3 (5 ())))
Any help would be appreciated...
I believe there's a problem with your implementation of zip, did you notice that you're returning a list of single-element lists of pairs? returning a list of pairs makes more sense:
(define (zip lst1 lst2)
(if (null? lst1)
'()
(cons (cons (car lst1) (car lst2))
(zip (cdr lst1) (cdr lst2)))))
Or even better, let's use the map higher-order function for a shorter, more idiomatic solution:
(define (zip lst1 lst2)
(map cons lst1 lst2))
Regarding unzip: it's easier if we split the problem in parts - let's get the first element of each pair, then the second element of each pair, and finally build a list with the answer. Try this:
(define (unzip lst)
(define (firsts lst)
(if (null? lst)
'()
(cons (caar lst)
(firsts (cdr lst)))))
(define (seconds lst)
(if (null? lst)
'()
(cons (cdar lst)
(seconds (cdr lst)))))
(list (firsts lst) (seconds lst)))
But once again, we're reinventing the wheel. Let's just use built-in functions to write a simpler answer:
(define (unzip lst)
(list (map car lst) (map cdr lst)))
Anyway, now unzip is the inverse of zip:
(zip '(1 3 5) '(2 4 6))
=> '((1 . 2) (3 . 4) (5 . 6))
(unzip '((1 . 2) (3 . 4) (5 . 6)))
=> '((1 3 5) (2 4 6))
As you make it with pairs it's somewhat more difficult but not much:
(define (zip-pair a b)
(map cons a b))
(define (unzip-pair zipped-pair)
(list (map car zipped-pair)
(map cdr zipped-pair)))
zip is usually implemented with apply and map and takes list and produce list of lists, like this:
(define (zip . lists)
(apply map list lists))
(zip '(1 2 3) '(a b c)) ; ==> ((1 a) (2 b) (3 c))
Though this will make lists and not pairs. However a unzip is almost the same except that you will take a list of lists instead of variable number of arguments:
(define (unzip1 zipped-list)
(apply map list zipped-list))
; or reuse zip
(define (unzip1 zipped-list)
(apply zip zipped-list))
(unzip1 '((1 a) (2 b) (3 c))) ; ==> ((1 2 3) (a b c))
This question already has answers here:
Searching and replacing n element on list - scheme
(2 answers)
Closed 8 years ago.
I want to change element in a list, >(change '(1 2 2 4) 2 5) so that the remaining elements in
the list will be (1 5 4).
(define change
(lambda (mylist num val)
(cond ((null? mylist) '())
(((equal? (car mylist) num) (cons val))
(change (cdr mylist) num val))
(else
(cons (car mylist)
(change (cdr mylist) num val))))))
So I changed the excessive and missing parens like I hinted in the comments and pressed CTRL+i and this is the result:
(define change
(lambda (mylist num val)
(cond ((null? mylist) '())
((equal? (car mylist) num) (cons val
(change (cdr mylist) num val)))
(else
(cons (car mylist)
(change (cdr mylist) num val))))))
Notice how (change ...) is the second argument to cons and it is placed right under on the same margin as val? Identation is very important for spotting errors so do press CTRL+i a lot! I would have moved the whole thing a little like this though:
(define change
(lambda (mylist num val)
(cond ((null? mylist) '())
((equal? (car mylist) num)
(cons val
(change (cdr mylist) num val)))
(else
(cons (car mylist)
(change (cdr mylist) num val))))))
Still. Se how (cons is rigth under (equal.. and not under the first paren while (else is? The identation tells you where cond clauses start and the structure of the code.
Looking at the code presented in your question the identation doesn't match the actual code since then (else..) would be in the (change.. list. It was actually impossible for me to see what was wrong before I reidented it.
I`m trying to implement a function that given an argument and a list, find that argument in the first element of the pair in a list
Like this:
#lang scheme
(define pairs
(list (cons 1 2) (cons 2 3) (cons 2 4) (cons 3 1) (cons 2 5) (cons 4 4)))
;This try only gets the first element, I need to runs o every pair on pairs
((lambda (lst arg)
(if (equal? (car (first lst)) arg) "DIFF" "EQ"))
pairs 2)
;This try below brings nok for every element, because Its not spliting the pairs
(define (arg) (lambda (x)2))
(map
(lambda (e)
(if (equal? arg (car e)) "ok" "nok"))
pairs)
The idea is simple, I have pair elements, and a given number. I need to see if the first element of the pairs (they are in a list) starts with that number
Thanks in advance
In Racket, this is easy to implement in terms of map. Simply do this:
(define (find-pair lst arg)
(map (lambda (e)
(if (equal? (car e) arg) "ok" "nok"))
lst))
Alternatively, you could do the same "by hand", basically reinventing map. Notice that in Scheme we use explicit recursion to implement looping:
(define (find-pair lst arg)
(cond ((null? lst) '())
((equal? (car (first lst)) arg)
(cons "ok" (find-pair (rest lst) arg)))
(else
(cons "nok" (find-pair (rest lst) arg)))))
Either way, it works as expected:
(find-pair pairs 2)
=> '("nok" "ok" "ok" "nok" "ok" "nok")
(find-pair pairs 7)
=> '("nok" "nok" "nok" "nok" "nok" "nok")
In Scheme, you should usually approach algorithms with a recursive mindset - especially when lists are involved. In your case, if you find the element in the car of the list then you are done; if not, then you've got the same problem on the cdr (rest) of the list. When the list is empty, you've not found the result.
Here is a solution:
(define (find pred list)
(and (not (null? list)) ; no list, #f result
(or (pred (car list)) ; pred on car, #t result
(find pred (cdr list))))) ; otherwise, recurse on cdr
With this your predicate function 'match if car of argument is n' is:
(define (predicate-if-car-is-n n)
(lambda (arg)
(eq? n (car arg))))
The above stretches your understanding; make sure you understand it - it returns a new function that uses n.
With everything together, some examples:
> (find (predicate-if-car-is-n 2) '((1 . 2) (2 . 3) (4 . 5)))
#t
> (find (predicate-if-car-is-n 5) '((1 . 2) (2 . 3) (4 . 5)))
#f
Let's say we have this list '( (4 (1 2)) (5 (5 5)) (7 (3 1)) (1 (2 3)))
I am trying to write smth in Scheme in order to get the second element for every element in the list.. So the result will look like '( (1 2) (5 5) (3 1) (2 3))
I have this code so far..
(define (second list1)
(if (null? (cdr list1))
(cdr (car list1))
((cdr (car list1))(second (cdr list1)))))
Here's a straightforward solution:
(define (seconds lst)
(map cadr lst))
In general, when you want to transform every element of a list, map is the way to go.
All you need to do is map the built-in function second onto the list lst:
(map second lst)
Your error is that you lack an operator, perhaps cons. If you look at the consequent:
((cdr (car list1))(second (cdr list1)))
So Scheme expects (cdr (car list)) to be a procedure since it's in operator position in the form, but since it isn't you get an error. In addition (cdr (car x)) == cdar wont take the second element in every element but the tail of each element. cadar is what you're lookig for.
(define (second list1)00+
(if (null? (cdr list1))
(cons (cadar list1) '())
(cons (cadar list1) (second (cdr list1)))))
It will fail for the empty list. To fix this you let the consequemt take care of every element and the base case only to stop:
(define (second list1)
(if (null? list1)
'()
(cons (cadar list1) (second (cdr list1)))))
The result for a list will be the same. There is a procedure called map. It supports several list arguments, but the implementation for one is:
(define (map fun lst)
(if (null? lst)
'()
(cons (fun (car lst)) (map fun (cdr lst)))))
Looks familiar? Both make a list based on each element, but map is generic. Thus we should try to make (fun (car lst)) do the same as (cadar lst).
(define (second lst)
(map cadr lst)) ; (cadr (car x)) == (cadar x)
There you have it. Chris beat me to it, but I'd like to comment one of the other answers that uses the abbreviation second. It's defined in racket/base and the library SRFI-1, but it's not mentioned in the last Scheme reports. I.e. some implementations might require an extra library to be imported for it to work.