(define (odds lst)
(if (null? lst)
lst
(cons (car lst)
(if (or (null? lst)
(not (pair? (cdr lst))))
'()
(odds (cddr lst)))))
)
This function returns the odd-numbered elements; my issue is, I want to take the list it returns and reverse it (using the built in reverse function). I've been trying to use lambda to store it but the results don't change, also tried using set-cons! also, to no avail. The concept of using let in a recursive function seems to escape me. If someone could point me in the right direction it would be very much appreciated!
Pass the function's result to reverse in the place where you want the reversed list:
> (odds '(a b c d e))
'(a c e)
> (reverse (odds '(a b c d e)))
'(e c a)
> (let ((o (reverse (odds '(a b c d e))))) (append o o))
'(e c a e c a)
> (define (reverse-odds ls) (reverse (odds ls)))
> (reverse-odds '(5 6 a 9 "hi"))
'("hi" a 5)
Here is a snippet storing both the return and the result using let*
(define (odds lst)
(if(null? lst)
lst
(cons (car lst)
(if (or (null? lst)
(not(pair? (cdr lst))))
'()
(odds (cddr lst))))))
(define data (odds `(1 2 3 4 5 6 7 8 9) ) )
(let ((rev_odds ( reverse data )))
;do stuff with results
(display rev_odds)
)
You can skip worrying about a return value if you just cons directly onto the recursive result
(define (odds lst)
(if (null? lst)
null
(if (odd? (car lst))
(cons (car lst)
(odds (cdr lst)))
(odds (cdr lst)))))
(odds '(0 1 2 3 4 5 6 7))
;; => '(1 3 5 7)
One way to represent a "return" value is by adding a parameter to our recursive function. Below we use acc in our auxiliary helper function, loop. Usage of parameters like this is one common way to move the recursive call into tail position
(define (odds lst)
(define (loop acc lst)
(if (null? lst)
(reverse acc)
(if (odd? (car lst))
(loop (cons (car lst) acc)
(cdr lst))
(loop acc
(cdr lst)))))
(loop null lst))
(odds '(0 1 2 3 4 5 6 7))
;; => '(1 3 5 7)
Another way is to represent our return value is by way of a lambda, cont below. We simply call cont with the value we wish to return. The recursive call looks a little more complicated in this case as we have to construct a lambda that represents the new return value. The added benefit here is odds constructs the result in order; reverse is no longer necessary
(define (odds lst (cont identity))
(if (null? lst)
(cont null)
(if (odd? (car lst))
(odds (cdr lst) (lambda (acc)
(cont (cons (car lst) acc))))
(odds (cdr lst) cont))))
(odds '(0 1 2 3 4 5 6 7))
;; => '(1 3 5 7)
Related
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)
I'm trying to write a code (function) using Scheme that:
Takes a list of any size as a parameter
Multiplies every number of the list together
Symbols should be skipped over
Values inside pairs should be included in multiplication
In other words, results should be as follows:
> (mult '(1 2 3))
6
> (mult '(1 2 x 3 4))
24
> (mult '(1 2 z (3 y 4)))
24 (mine gives me 2)
My code allows me to skip over the symbols and multiply everything. However, once I include a pair inside the list, it acts as though it isn't a number, therefore acting like it doesn't exist. Here's my code:
(define mult
(lambda (x)
(if (null? x)
1
(if(number? (car x))
(* (car x) (mult (cdr x)))
(mult(cdr x))))))
I've tried to use append when it finds a pair, but clearly I did it wrong... Any help on how I could get it to include the values inside a pair would be much appreciated.
i.e. '(1 2 y (3 z 4) = 1 * 2 * 3 * 4
You are nearly there, just missing the list? test:
(define (mult lst)
(if (null? lst)
1
(let ((ca (car lst)))
(cond
((number? ca) (* ca (mult (cdr lst))))
((list? ca) (* (mult ca) (mult (cdr lst))))
(else (mult (cdr lst)))))))
EDIT
He're an equivalent version without let:
(define (mult lst)
(cond
((null? lst) 1)
((number? (car lst)) (* (car lst) (mult (cdr lst))))
((cons? (car lst)) (* (mult (car lst)) (mult (cdr lst))))
(else (mult (cdr lst)))))
As you see, (car lst) is likely to be evaluated more than once, so I used let in the first version to avoid this.
It is a slightly advanced technique but this problem can easily be formulated as a tail recursive algorithm.
(define (mult lst)
(let multiplying ((lst lst) (r 1)) ; r is the multiplicative identity...
(if (null? lst)
r
(let ((next (car lst))
(rest (cdr lst)))
(multiplying rest (cond ((number? next) (* next r))
((list? next) (* (mult next) r))
(else r)))))))
> (mult '(1 2 3 a b (((((10)))))))
60
Using tail recursion has performance implications but, admittedly, it is not the first thing to learn - recursion is. However, in this case, because lists are often very long, avoiding a stack frame for each list element can be a dramatic savings; using tail calls avoids the stack frame.
I know this question has been asked before, and my solution is the same as many of the answers but I have a special test case that won't work correctly with the common solution to this problem.
The solution that I have found for the zip problem like many others is
(define (zip l1 l2)(map list l1 l2))
. . .which works great with given arguments such as
(zip '(a b c) '(1 2 3)) => ((a 1) (b 2) (c 3))
but I also want the zip function to work for cases where my arguments do not match length like
(zip '(a b c) '(1)) => ((a 1) (b ()) (c ()))
I have not found a solution to this problem and not really sure how to approach it where each list can be any length.
First, a simple iterative version that works for 2 lists only:
(define (zip lst1 lst2 (placeholder '()))
(define (my-car lst)
(if (empty? lst) placeholder (car lst)))
(define (my-cdr lst)
(if (empty? lst) lst (cdr lst)))
(let loop ((lst1 lst1) (lst2 lst2) (res '()))
(if (and (empty? lst1) (empty? lst2))
(reverse res)
(loop (my-cdr lst1) (my-cdr lst2)
(cons (list (my-car lst1) (my-car lst2)) res)))))
such as
(zip '(a b c) '(1 2 3))
=> '((a 1) (b 2) (c 3))
(zip '(a b c) '(1))
=> '((a 1) (b ()) (c ()))
From this, you can generalise to n lists, but to avoid keyword parameters you have to put the placeholder parameter first:
(define (zip placeholder . lsts)
(define (my-car lst)
(if (empty? lst) placeholder (car lst)))
(define (my-cdr lst)
(if (empty? lst) lst (cdr lst)))
(let loop ((lsts lsts) (res '()))
(if (andmap empty? lsts)
(reverse res)
(loop (map my-cdr lsts)
(cons (apply list (map my-car lsts)) res)))))
such as
(zip '() '(a b c) '(1 2 3))
==> '((a 1) (b 2) (c 3))
(zip '() '(a b c) '(1))
==> '((a 1) (b ()) (c ()))
(zip '() '(a b c) '(1) '(x y))
=> '((a 1 x) (b () y) (c () ()))
I believe that andmap is the only Racket-specific function here, which probably has some Scheme or SRFI equivalent depending on your implementation.
EDIT
Since the solution is based on creating lists of equal length, instead of duplicating the zip algorithm, you can also first add the placeholders to the lists before doing the classic map-list stuff:
(define (zip placeholder . lsts)
(let* ((max-len (apply max (map length lsts))) ; the length of the longest lists
(equal-length-lists ; adjusts all lists to the same length,
(map ; filling with placeholder
(lambda (lst) (append lst (make-list (- max-len (length lst)) placeholder)))
lsts)))
(apply map list equal-length-lists))) ; classical zip
It's not semantically correct to have (zip '(a b c) '(1)) => ((a 1) (b ()) (c ())) (unless you're specifically using () as a placeholder value); it's more sensible to have ((a 1) (b) (c)). Here's an implementation that achieves that:
(define (zip-with-uneven . lists)
(define (advance lst)
(if (null? lst)
lst
(cdr lst)))
(define (firsts lists)
(let loop ((lists lists)
(result '()))
(cond ((null? lists) (reverse result))
((null? (car lists)) (loop (cdr lists) result))
(else (loop (cdr lists) (cons (caar lists) result))))))
(let loop ((lists lists)
(results '()))
(if (andmap null? lists)
(reverse results)
(loop (map advance lists)
(cons (firsts lists) results)))))
andmap is from Racket. If you're not using Racket, you can use every from SRFI 1 instead.
If you really want to use a placeholder, here's a (Racket-specific) version that supports placeholders. The default placeholder is (void), which I presume is never a valid value you'd want to put in your result list.
(define (zip-with-uneven #:placeholder (ph (void)) . lists)
(define (advance lst)
(if (null? lst)
lst
(cdr lst)))
(define (cons-with-placeholder a d)
(if (void? a)
d
(cons a d)))
(define (firsts lists)
(let loop ((lists lists)
(result '()))
(cond ((null? lists) (reverse result))
((null? (car lists))
(loop (cdr lists) (cons-with-placeholder ph result)))
(else (loop (cdr lists) (cons (caar lists) result))))))
(let loop ((lists lists)
(results '()))
(if (andmap null? lists)
(reverse results)
(loop (map advance lists)
(cons (firsts lists) results)))))
This is my first experience with Scheme. I have a list with integers and I wanna get the sum of all even number in list.
; sum_even
(define (sum_even l)
(if (null? l) l
(cond ((even? (car l)) 0)
((not(even? (car l))) (car l)))
(+ (sum_even (car l) (sum_even(cdr l))))))
(sum_even '(2 3 4))
(define (sum_even l)
(cond ((null? l) 0)
((even? (car l)) (+ (car l) (sum_even (cdr l))))
(else (sum_even (cdr l)))))
Not tested
You're not exactly asking a question. Are you checking if your solution is correct or looking for an alternate solution?
You can also implement it as follows via
(apply + (filter even? lst))
edit: If, as you mentioned, you can't use filter, this solution will work and is tail-recursive:
(define (sum-even lst)
(let loop ((only-evens lst) (sum 0))
(cond
((null? only-evens) sum)
((even? (car only-evens))
(loop (cdr only-evens) (+ (car only-evens) sum)))
(else (loop (cdr only-evens) sum)))))
(define (sum-even xs)
(foldl (lambda (e acc)
(if (even? e)
(+ e acc)
acc))
0
xs))
Example:
> (sum-even (list 1 2 3 4 5 6 6))
18
Here is another one with higher order functions and no explicit recursion:
(use srfi-1)
(define (sum-even ls) (fold + 0 (filter even? ls)))
Consider using the built-in filter function. For example:
(filter even? l)
will return a list of even numbers in the list l. There are lots of ways to sum numbers in a list (example taken from http://groups.engin.umd.umich.edu/CIS/course.des/cis400/scheme/listsum.htm):
;
; List Sum
; By Jerry Smith
;
(define (list-sum lst)
(cond
((null? lst)
0)
((pair? (car lst))
(+(list-sum (car lst)) (list-sum (cdr lst))))
(else
(+ (car lst) (list-sum (cdr lst))))))