How to find the mean of a list with mixed symbols (numbers and characters) in scheme? - scheme

Given a list of the type '('a 1 'b 2 'c 3) I want to calculate the mean of the numbers in the list.
This is what I have done so far: I have written 3 functions that work correctly, one to remove the characters, the other to calculate the sum of the numbers in a list, and the other to find the average. But I do not know how to put them together to solve my problem.
;remove all non numbers from a list:
(define (all-numbers x)
(cond ((null? x) null)
((integer? (car x)) (cons (car x) (all-numbers (cdr x))))
(else (all-numbers (cdr x)))))
;sum the elements of the list
(define (sumlist lst)
(cond ((null? lst) 0)
(( + (car lst) (sumlist (cdr lst))))))
; find the mean of the list
(define (a_mean lst)
(cond ((null? lst) 0)
((/ (sumlist lst) (length lst)))))
(a_mean '(1 2 3))
;find the mean of a mixed list
(define (m_mean lst)
(cond ((null? lst) 0)
((/ (sumlist ((all-numbers lst)) (length (all-numbers lst)))))))
(m_mean '('a 1 'b 2 'c 3))
I get an error in the above code for m_mean. Please help! Thanks.

The answer by Óscar López should fix your problems.
I will now provide a more concise way of solving the same problem:
(define (m-mean lst)
(define all-numbers (filter number? lst)) ; Filter out all the non-numbers.
(if (null? all-numbers)
0 ; The mean is 0 if there are no numbers.
(/ (apply + all-numbers) (length all-numbers)))) ; Calculate mean.
This way, you do not have to explicitly define the all-numbers and sumlist functions.

For starters, some of your cond expressions are missing the else keyword in the final condition - this is mandatory, as you did in all-numbers. Also, in m_mean there are a couple of incorrect brackets; this should fix the errors:
(define (m_mean lst)
(cond ((null? lst) 0)
(else (/ (sumlist (all-numbers lst))
(length (all-numbers lst))))))
Now it works as expected:
(m_mean '(a 1 b 2 c 3))
=> 2

Related

Scheme, can someone explain how I'm using set-car! wrong?

I wanted to make a procedure that destructively increments the odd numbers of a list. I thought I'd recurse through it and just use 'set-car!' whenever 'odd?' was true.
Here is the code:
(define (test lst)
(cond ((null? lst) lst)
((odd? (car lst)) (set-car! lst (+ (car lst) 1))
(test (cdr lst)))
(else (test (cdr lst)))))
I'm not sure why it is not working, I guess I do not understand set-car! and set-cdr!
Could someone explain? Thank you.
The problem might be with your interpreter, or the language in which you're defining the procedure, or the way you're calling it. For instance, in DrRacket this works fine:
#lang r5rs
(define (test lst)
(cond ((null? lst) lst) ; this is the '() returned by the recursion
((odd? (car lst)) (set-car! lst (+ (car lst) 1))
(test (cdr lst)))
(else (test (cdr lst)))))
Bear in mind that your procedure will return an empty list, because that's the base case of the recursion and this is a tail-recursive procedure, which returns the value at the base case as its final result. But don't worry, the input list was modified in-place, you can check it after the procedure returns its value.
(define lst (list 1 2 3 4))
(display (test lst))
=> ()
(display lst)
=> (2 2 4 4)
See how mutability is confusing? a procedure is returning one value, but its input was modified and has a different value now. That's one of the reasons why functional programming (which favors immutable data) is cleaner and simpler to understand, and also demonstrates why is a bad idea to mutate input parameters inside a procedure ;)
If you absolutely want the procedure to return the mutated list, do as #sepp2k suggests, but remember - the input list was modified and in fact, is the same list that is returned as a result:
(define (test lst)
(cond ((null? lst) lst)
((odd? (car lst)) (set-car! lst (+ (car lst) 1))
(test (cdr lst))
lst) ; add this line
(else (test (cdr lst)))))
See for yourself:
(define lst (list 1 2 3 4))
(display (test lst))
=> (2 2 4 4)
(display lst)
=> (2 2 4 4)
was expecting the have the list containing (2 2 4 4) returned
The way you defined your function, it will return an empty list when called on the empty list and the result of the recursion in all other cases. So since the only base case is the empty list, you'll always return the empty list.
If you want to return the modified list, you'll need to do that after the recursion. That is after (test (cdr lst)), add lst to return the value of lst.
You are using set-car! correct. Here is how you tell it's working:
(define (test lst)
(cond ((null? lst) lst)
((odd? (car lst)) (set-car! lst (+ (car lst) 1))
(test (cdr lst)))
(else (test (cdr lst)))))
(define test-list (list 1 2 3 4))
(test test-list)
test-list ; ==> (2 2 4 4)
Your expectation that the function will return the modified list is wrong. To do that you need the first recursion step to return the argument. You need to wrap it:
(define (inc-odds lst)
(define (test lst)
(cond ((null? lst) lst)
((odd? (car lst)) (set-car! lst (+ (car lst) 1))
(test (cdr lst)))
(else (test (cdr lst)))))
(inc-odds lst) ; do the stuff
lst) ; return the list
(inc-odds (list 1 2 3 4)) ; ==> (2 2 4 4)
(inc-odds '(1 2 3 4)) ; ==> "pigs flying"
Notice the last one. In the RNRS upto R5RS passing a quoted literal to set-car! would produce an undefined behaviour which means anything is ok because technically the code isn't Scheme. In R6RS it's required to raise an exception.

Sum of all numbers in a list at the top level

I'm new to Scheme and I've spent about a week on this.
Write a Lisp function sumlist which takes a list and returns the sum of all the numbers in the list, at the top level. Thus,
(sumlist '(1 2 (3) (4 a) nil b 5)) should return 1+2+5=8. The numbers 3 and 4 are not at the top level. Use number? to check if a thing is a number."
This is what I have so far. It can recognize whether something is a number or not, but I can't get it to only add up the numbers on the top level.
(define (sumlist lst)
(cond ((null? lst) 0)
((number? lst) lst)
((list? lst)
(+ (sumlist (car lst)) (sumlist (cdr lst))))
(#t 0)))
; no values returned
> (sumlist '(1 2 (3) (4 a) nil b 5))
15
Any help is appreciated.
EDIT: Both Jedi's and Daniel's answers work. Thank you both very much.
I think it can be a bit simpler:
(define (sumlist lst)
(cond
((null? lst) 0)
((number? (car lst)) (+ (car lst) (sumlist (cdr lst))))
(else (sumlist (cdr lst)))))
Since you only care if an element is a number or not, you only have 3 cases.
(define (sumlist lst)
(cond ((null? lst) 0) ;; list is empty, we're done ;;
((number? (car lst)) (+ (car lst) (sumlist (cdr lst)))) ;; the first item is a number, so we add it to the rest
(else (sumlist (cdr lst))) ;; the first item was not a number, we just check the rest of the list
))

List order after duplicate filtering

I'm trying to teach myself functional language thinking and have written a procedure that takes a list and returns a list with duplicates filtered out. This works, but the output list is sorted in the order in which the last instance of each duplicate item is found in the input list.
(define (inlist L n)
(cond
((null? L) #f)
((= (car L) n) #t)
(else (inlist (cdr L) n))
))
(define (uniquelist L)
(cond
((null? L) '())
((= 1 (length L)) L)
((inlist (cdr L) (car L)) (uniquelist (cdr L)))
(else (cons (car L) (uniquelist (cdr L))))
))
So..
(uniquelist '(1 1 2 3)) => (1 2 3)
...but...
(uniquelist '(1 2 3 1)) => (2 3 1)
Is there a simple alternative that maintains the order of the first instance of each duplicate?
The best way to solve this problem would be to use Racket's built-in remove-duplicates procedure. But of course, you want to implement the solution from scratch. Here's a way using idiomatic Racket, and notice that we can use member (another built-in function) in place of inlist:
(define (uniquelist L)
(let loop ([lst (reverse L)] [acc empty])
(cond [(empty? lst)
acc]
[(member (first lst) (rest lst))
(loop (rest lst) acc)]
[else
(loop (rest lst) (cons (first lst) acc))])))
Or we can write the same procedure using standard Scheme, as shown in SICP:
(define (uniquelist L)
(let loop ((lst (reverse L)) (acc '()))
(cond ((null? lst)
acc)
((member (car lst) (cdr lst))
(loop (cdr lst) acc))
(else
(loop (cdr lst) (cons (car lst) acc))))))
The above makes use of a named let for iteration, and shows how to write a tail-recursive implementation. It works as expected:
(uniquelist '(1 1 2 3))
=> '(1 2 3)
(uniquelist '(1 2 3 1))
=> '(1 2 3)

Scheme write a function that returns number of odd numbers in a list

I'm having trouble writing a function in Scheme that returns the number of odd numbers in a list without using any assignment statements. I'm trying to use the predicate odd? as well. Any help/tips would be appreciated.
Ex: (odds '(1 2 3 4 5) // returns 3
Also, the list is of integers
Well, if no assignment statements can be used, you can still use the built-in procedures for this. In particular, count will work nicely in Racket:
(define (odds lst)
(count odd? lst))
... But I'm guessing that you're supposed to implement the solution from scratch. Some hints for finding the solution on your own, fill-in the blanks:
(define (odds lst)
(cond (<???> ; if the list is empty
<???>) ; then how many odd numbers are in it?
((odd? <???>) ; if the first element is odd
(<???> (odds <???>))) ; then add one and advance recursion
(else ; otherwise
(odds <???>)))) ; just advance the recursion
Anyway, it works as expected:
(odds '(1 2 3 4 5))
=> 3
Regardless if you use (R6RS?) Scheme or Racket, this will work for both:
(define (odds lst)
(length (filter odd? lst)))
(define l '(1 2 3 4 5 6 7 8 9 10))
(odds l)
As low level as I can get it :
(define odds
(lambda (lst)
(cond ((empty? lst) 0)
((not (= 0 (modulo (car lst) 2))) (+ 1 (odds (rest lst))))
(else (odds (cdr lst))))))
Here's another one-liner
(define (odds L)
(reduce + 0 (map (lambda (x) (if (odd? x) 1 0)) L)))
Here is a function that returns a function that counts anything based on a predicate:
(define (counter-for predicate)
(define (counting list)
(if (null? list)
0
(+ (if (predicate (car list)) 1 0)
(counting (cdr list)))))
counting))
which is used like:
(define odds (counter-for odd?))
[MORE OPTIONS] Here is a nice recursive solution
(define (odds list)
(if (null? list)
0
(+ (if (odd? (car list)) 1 0)
(odds (cdr list)))))
here is a tail recursive solution:
(define (odds list)
(let odding ((list list) (count 0)))
(if (null? list)
count
(odding (cdr list)
(+ count (if (odd? (car list)) 1 0))))))
Here is a routine that counts anything based on a predicate:
(define (count-if predicate list)
(if (null? list)
0
(+ (if (predicate (car list)) 1 0)
(count-if predicate (cdr list)))))

Scheme Factorial (fact* l) Question

I'm a newbie at Scheme, so forgive the question: I have a function that calculates the factorials of a list of numbers, but it gives me a period before the last number in the results. Where am I going wrong?
code:
#lang scheme
(define fact
(lambda (n)
(cond
((= n 0) 1)
((= n 1) 1)
(else (* n (fact (- n 1)))))))
(define fact*
(lambda (l)
(cond
((null? (cdr l)) (fact (car l)))
(else
(cons (fact (car l)) (fact* (cdr l)))))))
output:
> (fact* '(3 6 7 2 4 5))
(6 720 5040 2 24 . 120)
What you have done is create an improper list. Try this:
(define fact*
(lambda (l)
(cond
((null? (cdr l)) (list (fact (car l))))
(else
(cons (fact (car l)) (fact* (cdr l)))))))
The addition of the list in the fourth line should make this work as you expect. Better might be the following:
(define fact*
(lambda (l)
(cond
(null? l) '())
(else
(cons (fact (car l)) (fact* (cdr l)))))))
This allows your fact* function to work on the empty list, as well as reducing the number of places where you make a call to fact.
The other answers have pointed out the reason why you get an improper list as a result of your fact* function. I would only like to point out that you could use the higher-order function map:
(define fact*
(lambda (l)
(map fact l))
(fact* '(3 6 7 2 4 5))
map takes a function and a list as arguments and applies the function to every element in the list, producing a new list.
Use append instead of cons. cons is used to construct pairs, which is why you have the "." that is used to separate the elements of a pair. Here's an example:
(define (factorial n)
(if (<= n 1)
1
(* n (factorial (- n 1)))))
(define (factorial-list l)
(if (null? l)
'()
(append (list (factorial (car l)))
(factorial-list (cdr l)))))

Resources