scheme sum of the numbers in a list - list

I am writing a function which give the sum of all the number in a list neglecting words or alphabets.
(define (sum-list ls)
(cond ((null? ls) 0)
((not (number? (car ls))) (sum-list(cdr ls)))
(else (+ (car ls) (sum-list (cdr ls))))
)
)
(deep-sum '(a 2 (b (1 c)) 3)) => ; should return 6.
but i am getting 5. that mean my code is not reaching in the inner loop

That's not the way to traverse a list of lists, it goes more like this:
(define (deep-sum ls)
(cond ((null? ls) 0)
((not (pair? ls)) ; only add atoms
(if (number? ls) ls 0)) ; only add numbers
(else (+ (deep-sum (car ls)) ; advance recursion on both car and car
(deep-sum (cdr ls))))))
Now it works as expected:
(deep-sum '(a 2 (b (1 c)) 3))
=> 6

If you want to check nested lists, you must have another condition that checks if the element is a list, and then call sum-list recursively.
Adding this line below the null? condition should do it.
((list? (car ls)) (+ (sum-list (car ls)) (sum-list (cdr ls))))

Related

Storing return values in Scheme

(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)

Scheme zip function with possible uneven lists

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)))))

MIT Scheme List Sorted in Ascending order

I'm taking a practice exam for a course in programming that deals with MIT Scheme. One of the questions asks:
"Complete the procedure (in-order ls) to return the list ls, except stop just before the first value that is not strictly greater than the previous value in ls. In other words, in-order should return the portion of ls starting from the beginning that is sorted in strictly increasing order. Assume that ls contains only non-negative integers."
The question then shows several examples:
(in-order '(1 2 3 4)) ; should return (1 2 3 4)
(in-order '(1 2 3 3 4 5)) ; should return (1 2 3)
(in-order '(3 2)) ; should return (3)
(in-order '(3)) ; should return (3)
This is my attempt at a solution:
(define (in-order ls)
(cond ((null? ls) ls)
((< (car ls) (cadr ls))
(cons (car ls) (cons (in-order (cdr ls)) ())))
((>= (car ls) (cadr ls)) (car ls))
(else "Nothing")))
It comes close to working with the 2nd and 3rd example, but outright fails with the 1st and 4th example. I know that it keeps trying to pass a null as part of the argument, but I'm unsure of how to work around this. Other than that, is there anything else that I'm getting wrong?
This gets you there:
(define (in-order ls)
(if (null? ls)
'()
(let looking ((result (list (car ls))) (ls (cdr ls)))
(if (or (null? ls) (not (< (car result) (car ls))))
(reverse result)
(looking (cons (car ls) result)
(cdr ls))))))
The tail recursive looking always has the last value as the result's car. So the comparison for stopping becomes (not (< (car result) (car ls)))
In your code the (cons (in-order ...) ()) is almost surely wrong. The predicate (< (car ls) (cadr ls)) will fail on anything like '(3) - you need something like (null? (cdr ls)) to avoid that.
In a non-tail recursive algorithm, similar to yours, it would be:
(define (in-order ls)
(cond ((or (null? ls) (null? (cdr ls))) ls) ; nothing left
((< (car ls) (cadr ls)) ; extend and continue
(cons (car ls) (in-order (cdr ls))))
(else (list (car ls))))) ; last one

Scheme: Remove duplicated numbers from list

I wrote this code to create a list from en number of arguments given
(define (create-list . e)
e)
But I need it to remove any duplicated numbers from the list within this block itself.
I have tried and searched for hours and can't find a solution without placing dozens of lines of code on other blocks.
For example let's say my input is
(create-list . 2 2 3 5 5 )
I need the list created to be '(2 3 5) and not '(2 2 3 5 5 )...
The order of the numbers doesn't matter.
Basically, you need to do something like:
(define (create-list . e) (dedupe e))
I can think of a really simple but probably inefficient way to do this:
(define (dedupe e)
(if (null? e) '()
(cons (car e) (dedupe (filter (lambda (x) (not (equal? x (car e))))
(cdr e))))))
If you can't use existing functions like filter, you can make one yourself:
(define (my-filter pred ls)
(cond ((null? ls) '())
((pred (car ls)) (cons (car ls) (my-filter pred (cdr ls))))
(else (my-filter pred (cdr ls)))))
This one is faster:
(define (remove-duplicates l)
(cond ((null? l)
'())
((member (car l) (cdr l))
(remove-duplicates (cdr l)))
(else
(cons (car l) (remove-duplicates (cdr l))))))
But even better,
mit-scheme provides delete-duplicates, which does exactly what you want.
The most efficient (traversing the list once) way to do this is to define a function which goes through the list element-by-element. The function stores a list of which elements are already in the de-duped list.
An advantage of this solution over #Tikhon Jelvis's, is that the list elements don't need to be in order, to be deduplicated.
Given a function elem, which says if a is an element of l:
(define (elem? a l)
(cond ((null? l) #f)
((equal? a (car l)) #t)
(else (elem? a (cdr l)))))
We can traverse the list, storing each element we haven't seen before:
(define (de_dupe l_remaining already_contains)
(cond ((null? l_remaining) already_contains)
((elem? (car l_remaining) already_contains) (de_dupe (cdr l_remaining) already_contains))
(else (de_dupe (cdr l_remaining) (cons (car l_remaining) already_contains)))))
Note: for efficiency, this returns the elements in reverse order
(define (delete x)
(cond
((null? x) x)
((= (length x) 1) x) | ((null? (cdr x)) x)
((= (car x) (cadr x)) (delete (cdr x)))
(#t (cons (car x) (delete (cdr x))))
)
)

Sum of even in Scheme

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))))))