problem takes a list e.g L = (4 11 16 22 75 34) and gets tested for a condition (modulus 2) then returns a list with all the items in the list that pass the test e.g newL = (4 16 34)
Here is the code:
(define clean-list
(lambda (x)
(list x (test x))))
(define test
(lambda (x)
(cond (= 0 (modulo (car x) 2))
(cons (car x) (test(cdr x)))
(else (test(cdr x))))
))
output:
((4 11 16 22 75 34) 0)
I debugged the code, it foes into (modulo (car x) 2) then returns to clean-list and exits, all after first run, please explain that and why it returns a 0 at the end of list. Also any feedback or improvement in code would be appreciated.
You're missing a set of parentheses. You're also missing a test for the recursion bottoming out.
(define test
(lambda (x)
(cond ((eq? x '()) '())
((= 0 (modulo (car x) 2))
(cons (car x) (test(cdr x))))
(else (test(cdr x))))
))
DEMO
The general syntax of cond is:
(cond (<test1> <result1>)
(<test2> <result2>)
...)
In your code <test1> was simply =, not (= 0 (modulo (car x) 2)).
Here's a tail-recursive version of the function.
(define test
(lambda (x)
(define (helper in out)
(if (null? in)
out
(if (= 0 (modulo (car in) 2))
(helper (cdr in) (append out (list (car in))))
(helper (cdr in) out))))
(helper x '())
))
(define clean-list
(lambda (x)
(list x (test x))))
(write (clean-list '(4 11 16 22 75 34)))
The output:
((4 11 16 22 75 34) (4 16 22 34))
PS. When I tested the code at repl.it, I had to change modulo to mod.
Related
I started learning Scheme today, and wanted to write a function that would reverse a list (only surface level, nested lists stay in the same order).
Heres the function I made:
(define reverse (lambda (lst)
(if (> (length lst) 0)
(cons (reverse(cdr lst)) (car lst))
'()
)))
I thought it would just continuously add the values before everything after it so in the end it's reversed, but when doing (reverse '(5 12 31 7 98 13)), I should get (13 98 7 31 12 5), but instead I get '((((((() . 13) . 98) . 7) . 31) . 12) . 5). How come it's adding periods and parenthesis instead of adding the number to the list?
(list x y ..... z) list structure is constructed like this in Scheme:
(cons x
(cons y
…
…
(cons z '())))
if you use append instead of cons and put your (car lst) into a list of its own, your code will work:
(define reverse
(lambda (lst)
(if (> (length lst) 0)
;;(cons (reverse (cdr lst)) (car lst) )
(append (reverse (cdr lst)) (list (car lst)))
'()
)))
The list (13 98 7 31 12 5) is a visualization of the pairs (13 . (98 . (7 . (31 . (12 . (5 . ())))))). If the cdr is a pair or the empty list the dot and one set of parens is omitted. The code to create this structure is (cons 13 (cons 98 (cons 7 (cons 31 (cons 12 (cons 5 '())))))) while the structure your function creates is (cons (cons (cons (cons (cons (cons 13 '()) 98) 7) 31) 12) 5).
When iterating a list you always do it in order. eg. (1 2 3) is quite difficult to do in reverse. However when creating lists you always do them from end to beginning. eg. (cons 1 (cons 2 (cons 3 '()))) will have to evaluate the cons with 3 before the one with 2 etc. This can be used for a very efficent reverse using an accumulator:
(define (reverse lst acc)
(if (null? lst)
acc
(reverse (cdr lst)
(cons (car lst) acc))))
So imagine calling this (reverse '(1 2 3) '()):
(reverse '(1 2 3) '()) ; =>
(reverse '(2 3) (cons 1 '())) ; ==>
(reverse '(3) (cons 2 '(1))) ; ==>
(reverse '() (cons 3 '(2 1))) ; ==>
'(3 2 1)
I am working my first project in scheme and have come across an issue. In part of my requirements, I am required to append all top-level sublists
(e.g. '((1 2)(3 4 (5 6))) -> (1 2 3 4 (5 6)) and '((1 2 3)(4 5)) -> (1 2 3 4 5)
I've managed to get it working down to a single list, but this flattens all levels:
(cond
((null? lst)
lst)
((list? lst)
(append2(append-subs(car lst))(append-subs(cdr lst))))
(else
(cons lst '())))
Variations of this (eg. (else lst) run the error "object 6, passed as first arg to cdr, is not correct type". Another method I attempted is as follows:
(cond
((null? lst)
lst)
((>= (len (cdr lst)) 0)
(append2(append-subs(car (list lst)))(append-subs(cdr (list lst)))))
(else
lst)
Which infinitely loops. I'm at a bit of a stand still, so any help would be greatly appreciated. (Note: Use of functions other than those used here is forbidden. Limited to list, list?, if, cond, null? ...)
Your list '(e1 e2 e3) would be like this:
(cons e1 (cons e2 (cons e3 '())))
or if you like dotted notation:
'(e1 . (e2 . (e3 . ())))
Where en is eiter #f or #t for (list? en) Your assignment is to cons en onto the recursion with the same level while with a list you need to append the two.
Here is a general idea how to implement it with level as an input parameter:
;;; flatten a list a certain levels
;;; level of zero is identity
(define (flatten-level level lst)
(cond ((or (zero? level)
(null? lst))
lst)
;; pair? is faster but will fall through for dotted
((list? (car lst))
(append (flatten-level <??> <??>)
(flatten-level <??> <??>)))
(else
(cons <??>
(flatten-level <??> <??>)))))
(flatten-level 0 '((1 2)(3 (((4 . 3))) (5 (6))) . 7))
; ==> ((1 2) (3 (((4 . 3))) (5 (6))) . 7) (aka identity)
(flatten-level 1 '((1 2)(3 (((4 . 3))) (5 (6))) . 7))
; ==> (1 2 3 (((4 . 3))) (5 (6)) . 7)
(flatten-level 99 '((1 2)(3 (((4 . 3))) (5 (6))) . 7))
; ==> (1 2 3 (4 . 3) 5 6 . 7)
How about appending all elements of the top list:
(define (flatten-top-level lst)
(apply append lst))
Which is practically the definition of append*
If '(a (b) (c f)) is a valid input, (first element not a list) then you can try:
(define (flatten-top-level lst)
(apply append
(map (lambda (e) (if (list? e)
e
(list e))) ;make a list from the non-list element
lst)))
2nd option: Fold it!
(define (flatten-top-level lst)
(foldr append '() lst))
For a list (a b c d) where a, b, c, d are sub-lists; it is equal to:
(append a (append b (append c (append d '()))))
Extra: this is tail recurssive and therefore runs in linear time :)
I am trying to learn clisp and I have started learning how to manipulate lists recursively. I am unsure wether it is my logic or if I am just too unfamiliar with the constructs of lisp, for some I am able to do it i.e. for procedure (separate '(a 1 b 2 c 3 d 4)) => ((1 2 3 4) (a b c d)) by doing
(defun separate (lst)
(if (endp lst)
'(nil nil)
(let ((x (separate (cdr lst))))
(if (numberp (car lst))
(list (cons (car lst)
(car x)))
(list (car x)
(cons (car lst) (cadr x)))))))
but when I do the same approach for another procedure
(greater-than-n '(9 1 8 2 7 3 6 4) 5)
I would expect to get a list : ((9 8 7 6) (1 2 3 4))
but instead I get: ((9 8 7 6))
My program thus far is:
(defun greater-than-n (lst n)
(if (endp lst)
'(() ())
(let ((x (greater-than-n (cdr lst) n)))
(if (> (car lst) n)
(list (cons (car lst)
(car x)))
(list (car x)
(cons (car lst)
(car x)))))))
I appreciate any help or comments.
Your bug is in the
(list (cons (car lst)
(car x)))
form: you are returning a list of 1 element.
PS. Your functions seem like a textbook case for using multiple values instead of a list of values.
I want to duplicate every found element in a list. I have the idea but i can't make it right. Sample input is >(pass '(1 2 3 4 4)) will have the output (1 1 2 2 3 3 4 4 4 4). Anyone out there help me. Here is my code ..
(define duplicate
(lambda (mylist n)
(cond ((null? mylist) "Not found")
((< n 2) (cons (car mylist)
(duplicate mylist (+ n 1))))
(else
(duplicate (cdr mylist) 0)))))
(define pass
(lambda (mylist)
(duplicate list 0)))
I will appreaciate all valuable comments.
Just a couple of fixes (see the comments) and we're good to go:
(define duplicate
(lambda (mylist n)
(cond ((null? mylist) '()) ; base case must return the empty list
((< n 2) (cons (car mylist)
(duplicate mylist (+ n 1))))
(else
(duplicate (cdr mylist) 0)))))
(define pass
(lambda (mylist)
(duplicate mylist 0))) ; pass myList, not list
Notice that the procedure can be simplified a bit:
(define (pass lst)
(if (null? lst)
'()
(cons (car lst)
(cons (car lst)
(pass (cdr lst))))))
Or even better, using higher-order procedures for a more idiomatic solution:
(define (pass lst)
(foldr (lambda (ele acc) (list* ele ele acc))
'()
lst))
Yet another alternative:
(define (pass lst)
(append-map (lambda (ele) (list ele ele))
lst))
Anyway, it works as expected:
(pass '(1 2 3 4 4))
=> (1 1 2 2 3 3 4 4 4 4)
I would do it so:
(define (dup l)
(define (iter l co)
(if (null? l)
(co '())
(iter (cdr l)
(lambda (x)
(co (cons (car l) (cons (car l) x)))))))
(iter l (lambda (x) x)))
(dup '(1 2 3))
It may be simpler to treat duplicate as zipping a list with itself. Then flattening the resulting list.
In Scheme or Racket:
(require srfi/1)
(define (duplicate-list-members lox)
(flatten (zip lox lox)))
Though it runs in O(n) time, profiling may indicate that passing through the list twice is a bottleneck and justify rewriting the function. Or it might not.
Try using map and list
(define (duplicate my-list)
(flatten
(map
(lambda (x)
(list x x))
my-list)))`
Gives requested format:
> (duplicate (list 1 2 3 4 4))
'(1 1 2 2 3 3 4 4 4 4)
IN SCHEME
I am trying to write a section of code to sort a list of sublists, using the difference between to elements of each sublist. What i mean is:
ie.,
list of sublists: '('(ted 10 4) '(barbie 10 5) '(car 10 7) '(ball 10 6))
and i want to sort the list based on the difference between the 2nd and 3rd element of each sublist list thus the sorted list should look like in ascending order (lowest to highest):
'('(car 10 7) '(ball 10 6) '(barbie 10 5) '(teddy 10 4))
I have created accessors for the sublists:
(define (access-name x) (car x))
(define (access-aquprice x)(cadr x))
(define (access-saleprice x)(caddr x))
the sort loop is confusing me,please help! :)
So far all I have is:
(define (sortlist curr)
(if (null? curr)
(curr)
(if (>
(diff (access-aquprice (car toylist)) (access-saleprice (car toylist)))
(diff (access-aquprice (cadr toylist)) (access-saleprice (cadr toylist))))
("hello")
"goodbye")))
Disclaimer: this is the first sort I ever write myself. It may not be bug-free
So you first have to write a basic sort. I suggest you look at this page and pick one. I chose Merge sort since the Wikipedia illustration is nice and it's easy to implement it recursively.
We'll start with sorting a simple list.
So, first the merge:
(define (merge lst1 lst2)
(cond
((null? lst1) lst2)
((null? lst2) lst1)
((> (car lst1) (car lst2))
(cons (car lst2) (merge lst1 (cdr lst2))))
(else
(cons (car lst1) (merge (cdr lst1) lst2)))))
then the merge sort:
(define (merge-sort lst)
(define len (length lst))
(if (<= len 1)
lst
(let ((n (quotient len 2)))
(merge (merge-sort (take lst n)) (merge-sort (drop lst n))))))
(take and drop are defined in SRFI-1 if needed)
Trying:
> (merge-sort '(7 3 0 1 5 8))
'(0 1 3 5 7 8)
> (merge-sort '())
'()
> (merge-sort '(3 14 15 9 26 53 58 97 23))
'(3 9 14 15 23 26 53 58 97)
Looks nice.
Now we'll extend it to use a custom compare function:
(define (merge-sort compare lst)
(define (merge lst1 lst2)
(cond
((null? lst1) lst2)
((null? lst2) lst1)
((compare (car lst1) (car lst2))
(cons (car lst2) (merge lst1 (cdr lst2))))
(else
(cons (car lst1) (merge (cdr lst1) lst2)))))
(define (inner-sort lst)
(define len (length lst))
(if (<= len 1)
lst
(let ((n (quotient len 2)))
(merge (inner-sort (take lst n)) (inner-sort (drop lst n))))))
(inner-sort lst))
then
> (merge-sort > '(7 3 0 1 5 8))
'(0 1 3 5 7 8)
> (merge-sort < '(7 3 0 1 5 8))
'(8 7 5 3 1 0)
Finally, creating a custom compare function for your case:
(merge-sort
(lambda (a b) (> (- (access-aquprice a) (access-saleprice a))
(- (access-aquprice b) (access-saleprice b))))
'((ted 10 4) (barbie 10 5) (car 10 7) (ball 10 6)))
yields
'((car 10 7) (ball 10 6) (barbie 10 5) (ted 10 4))
I know that the question is 3 years old, and you are not allowed to use the built-in sort function, but just in case somebody needs it:
(sort (lambda (x y) (< (- (cadr x) (caddr x))
(- (cadr y) (caddr y))))
'((ted 10 4) (barbie 10 5) (car 10 7) (ball 10 6)))
returns ((car 10 7) (ball 10 6) (barbie 10 5) (ted 10 4))
Cheers!
Andres