I'm trying to create a function to count all the elements in a list, including the elements of its sublists. initially, to get started, i came up with a basic function myList:
(define myLength
(lambda (L)
(cond
((null? L) 0)
(else (+ 1 (myLength (cdr L)))))))
However, it doesn't help me account for function calls like:
(numAtoms '()) "...should be 0"
(numAtoms '(())) "...should be 0"
(numAtoms '(1 1)) "...should be 2"
(numAtoms '(1 (1 1) 1)) "...should be 4"
(numAtoms '(1 (1 (1 1)) 1)) "...should be 5"
I'm trying to use basic functions like length, null?, and list?.
I think the trick here is to imagine how you can transform your input into the code that you'd want to use to compute the sum. Let's write each of your inputs in the fully expanded form, in terms of cons and '() and whatever other atoms appear in your data:
'() == '()
'(()) == (cons '() '())
'(1 1) == (cons 1 (cons 1 '()))
'(1 (1 1) 1) == (cons 1 (cons 1 (cons 1 '())) (cons 1 '()))
'(1 (1 (1 1)) 1) == ...
Now, look what would happen if you replaced each occurrence of cons with +, and each occurrence of '() with 0, and each occurrence of something that's not '() with 1. You'd have:
'() => 0 == 0
(cons '() '()) => (+ 0 0) == 0
(cons 1 (cons 1 '())) => (+ 1 (+ 1 0)) == 2
(cons 1 (cons 1 (cons 1 '())) (cons 1 '())) => (+ 1 (+ 1 (+ 1 0)) (+ 1 0)) == 4
... => ... == ...
Notice that those sums are exactly the values that you want! Based on this, it seems like you might not want to treat your input as a list so much as a tree built from cons cells. In general, you can map over a tree by specifying a function to apply to the recursive results of processing a pair, and a function to process the atoms of the tree:
(define (treeduce pair-fn atom-fn tree)
(if (pair? tree)
(pair-fn (treeduce pair-fn atom-fn (car tree))
(treeduce pair-fn atom-fn (cdr tree)))
(atom-fn tree)))
You could then implement that mapping of cons to + and everything else to 1 if it's a list and 0 if it's not by:
(define (non-null-atoms tree)
(treeduce +
(lambda (atom)
(if (not (null? atom))
1
0))
tree))
This yields the kinds of results you'd expect:
(non-null-atoms '()) ;=> 0
(non-null-atoms '(())) ;=> 0
(non-null-atoms '(1 1)) ;=> 2
(non-null-atoms '(1 (1 1) 1)) ;=> 4
(non-null-atoms '(1 (1 (1 1)) 1)) ;=> 5
Here is a recursive template you can use:
(define (num-atoms lst)
(cond ((pair? lst) (+ (num-atoms <??>)
(num-atoms <??>)))
((null? lst) <??>) ; not an atom
(else <??>))) ; an atom
This next example uses a helper that has the accumulated value (num) as an argument.
(define (num-atoms lst)
;; locally defined helper
(define (helper num lst)
(cond ((pair? lst) (helper (helper <??> <??>) <??>)) ; recurse with the sum of elements from car
((null? lst) <??>) ; return accumulated value
(else (helper <??> <??>)))) ; recurse with add1 to num
;; procedure starts here
(helper 0 lst))
Hope it helps
Make my-length work for any argument type, list or 'atom'; then the recursive algorithm becomes almost trivial:
(define (my-length l)
(cond ((null? l) 0)
((list? l) (+ (my-length (car l)) (my-length (cdr l))))
(else 1))) ; atom
> (my-length '(1 (1 (1 1)) 1)))
5
Related
Here is my code. My test result are always wrong and I don't know where the mistakes are and how to correct them.
(define (calculator op num lst)
(cond [(empty? lst) empty]
[else (cons (op num (first lst))
(calculator op num (rest lst)))]))
(define (sb lst)
(calculator - 2 lst))
(define (calculator op num lst)
; test result:
(sb (list 2 3))
-->(list 0 -1)
(sb (list 5 6))
-->(list -3 -4)
(sb (list -1 -2))
-->(list 3 4)
The problem is caused by (op num (first lst)). When you run your code, it is essentially equivalent to (- 2 (first lst)). You are not subtracting 2 from every item in the list. Instead you are subtracting every item in the list from 2. You are doing 2 - x instead of x - 2. To get the desired results, the arguments given to - should be flipped.
You could solve the problem by defining a "flipped subtraction" function that takes its arguments in a different order. For example:
(define (flipped-sub b a)
(- a b))
(define (sb lst)
(calculator flipped-sub 2 lst))
Or just use an anonymous lambda:
(define (sb lst)
(calculator (lambda (num x) (- x num)) 2 lst))
I am encountering a issue that I need to add up the second number of each list. For example, suppose I have a list of lists like below,
(list (list -4
(list (list -1 4) (list 1 7)))
(list 1 (list (list -2 5) (list 3 3)))
(list 3 12))
Then my job is to add up 4 + 7 + 5 + 3 + 12 = 31. However, the list can have multiple sub lists. But the second item inside a list can either be a number or a list. If it is a list, then we need to dig deeper into this list until we get a number.
Thanks!
Solution
(define (atom? x)
(and (not (null? x))
(not (pair? x))))
(define (my-and x y)
(and x y))
(define (every? l)
(foldr my-and #t l))
(define (flat-list? l)
(cond ((null? l) #t)
((every? (map atom? l)) #t)
(else #f)))
(define (add-only-seconds l)
(define (l-sec-add l acc)
(cond ((null? l) acc)
((atom? l) acc)
((flat-list? l) (+ (second l) acc))
((list? l) (apply + acc (map (lambda (x) (l-sec-add x 0)) l)))))
(l-sec-add l 0))
Example test
(define example-list (list (list -4
(list (list -1 4) (list 1 7)))
(list 1 (list (list -2 5) (list 3 3)))
(list 3 12)))
(add-only-seconds example-list) ;; 31
I used common-lisp-typical functions atom? and every?.
Since and cannot be used in foldr, I defined my-add to make add a function which can be used infoldr`.
I am following the cs61a spring 2015 class.
One of the problem in the scheme project is:
Implement the list-partitions procedure, which lists all of the ways to
partition a positive integer total without using consecutive integers. The
contents of each partition must be listed in decreasing order.
Hint: Define a helper procedure to construct partitions. The built-in append
procedure creates a list containing all the elements of two argument lists.
The cons-all procedure in questions.scm adds a first element to each list in a list of lists.
The number 5 has 4 partitions that do not contain consecutive integers:
5
4, 1
3, 1, 1
1, 1, 1, 1, 1
The following partitions of 5 are not included because of consecutive
integers:
3, 2
2, 2, 1
2, 1, 1, 1
I found one solution but cannot understand it
;; List all ways to partition TOTAL without using consecutive numbers.
(define (apply-to-all proc items)
(if (null? items)
'()
(cons (proc (car items))
(apply-to-all proc (cdr items)))))
(define (cons-all first rests)
(apply-to-all (lambda (rest) (cons first rest)) rests))
(define (caar x) (car (car x)))
(define (cadr x) (car (cdr x)))
(define (cddr x) (cdr (cdr x)))
(define (cadar x) (car (cdr (car x))))
(define (cdar x) (cdr (car x)))
(define (partitions-r a b)
(if (= a 0) nil
(append (cons-all a (list-partitions b))
(cons-f (partitions-r (- a 1) (+ b 1))
))
))
(define (cons-f lst)
(cond
((eq? lst nil) nil)
((eq? (cdar lst) nil) lst)
((< (caar lst) (cadar lst)) (cons-f (cdr lst)))
((= (caar lst) (+ 1 (cadar lst))) (cons-f (cdr lst)))
(else (cons (car lst) (cons-f (cdr lst))))
))
(define (list-partitions total)
(cond ((= total 1) '((1)) )
((= total 0) '(()) )
(else (append nil (partitions-r total 0)))
))
; For these two tests, any permutation of the right answer will be accepted.
(list-partitions 5)
; expect ((5) (4 1) (3 1 1) (1 1 1 1 1))
(list-partitions 7)
; expect ((7) (6 1) (5 2) (5 1 1) (4 1 1 1) (3 3 1) (3 1 1 1 1) (1 1 1 1 1 1 1))
What does the function partitions-r and cons-f do? Thank you very much!
Don't know Scheme, but recursive generation in pseudocode might look like:
function Partitions(N, LastValue, list):
if N = 0
print list
else
for i from Min(LastValue, N) downto 1
if (i != LastValue - 1) //reject consecutive number
Partitions(N - i, i, list + [i]);
What I need to add to count the number of zeros only in the even lists?
For example,
(count-zeroes '((1 1 1) (1 0 0) (1 1 1) (1 0 0)))
4
it is for one list.
(define count-zeroes
(lambda (list)
(cond ((null? list) 0)
((= 0 (car list)) (+ 1 (count-zeroes (cdr list))))
(else (+ 0 (count-zeroes (cdr list))))
)
)
)
(define count-zeroes
(lambda (list)
(cond ((null? list) 0) ; a
((= 0 (car list)) (+ 1 (count-zeroes (cdr list)))) ; b
(else (+ 0 (count-zeroes (cdr list))))))) ; c
If list is initially a list of lists, then (null? list) in line a can be true (when you get to the end of the list), but the condition (= 0 (car list)) in the line b will never be true, since (car list) will always be another list, and 0 isn't a list.
A better way to break this down would probably be to first extract the even positioned sublists, then flatten them into a single list, and then count the zeros in those. That's not the most efficient way to do it (you'll create some intermediate storage), but you should probably implement something like that first, and then gradually optimize it afterward.
It's also worth noting that lists are typically indexed starting with position zero, so the second, fourth, etc., elements in the list are the ones with odd positions, not even positions. Here's the kind of abstraction that might help you in getting started with this kind of approach:
(define first car)
(define rest cdr)
(define list* cons)
(define (odds list)
(if (null? list) '()
(evens (cdr list))))
(define (evens list)
(if (null? list) '()
(list* (first list)
(odds (rest list)))))
(define sample '((0 0 1) (0 1 0) (0 1 1) (1 0 0) (1 0 1) (1 1 0) (1 1 1)))
;; (display (odds sample))
;; => ((0 1 0) (1 0 0) (1 1 0))
An interesting question. If you are operating on a lists of lists you need to add car-cdr recuresion.
(define (count-zeroes lst) ;;don't override core function names with a variable
(cond ((null? lst) 0)
((pair? (car lst))
(+ (count-zeroes (car lst))
(count-zeroes (cdr lst))))
((= 0 (car lst))
(+ 1 (count-zeroes (cdr lst))))
(else (count-zeroes (cdr lst))))))
No as to only evens you are no longer counting zeros, so a new function name is in order. You could make up a higher order function like this.
(define (count-zeros-of selector lst)
(count-zeroes (selector lst)))
And make a general selector
(define (take-every-Xnth-at-y x y lst)
(cond ((null? lst) '())
((= y 0) (cons (car lst)
(take-every x (- x 1) (cdr lst))))
(else (take-every x (- y 1) (cdr lst)))))
To put it all together
(define (count-zeroes-of-even lst)
(count-zeroes-of
(lambda (lst) ;;to bad we can't do partial application
(take-every-Xnth-at-y 2 1 lst))
lst)
Note each of these parts do their one thing and do it well.
I don't fully understand what the append-map command does in racket, nor do I understand how to use it and I'm having a pretty hard time finding some decently understandable documentation online for it. Could someone possibly demonstrate what exactly the command does and how it works?
The append-map procedure is useful for creating a single list out of a list of sublists after applying a procedure to each sublist. In other words, this code:
(append-map proc lst)
... Is semantically equivalent to this:
(apply append (map proc lst))
... Or this:
(append* (map proc lst))
The applying-append-to-a-list-of-sublists idiom is sometimes known as flattening a list of sublists. Let's look at some examples, this one is right here in the documentation:
(append-map vector->list '(#(1) #(2 3) #(4)))
'(1 2 3 4)
For a more interesting example, take a look at this code from Rosetta Code for finding all permutations of a list:
(define (insert l n e)
(if (= 0 n)
(cons e l)
(cons (car l)
(insert (cdr l) (- n 1) e))))
(define (seq start end)
(if (= start end)
(list end)
(cons start (seq (+ start 1) end))))
(define (permute l)
(if (null? l)
'(())
(apply append (map (lambda (p)
(map (lambda (n)
(insert p n (car l)))
(seq 0 (length p))))
(permute (cdr l))))))
The last procedure can be expressed more concisely by using append-map:
(define (permute l)
(if (null? l)
'(())
(append-map (lambda (p)
(map (lambda (n)
(insert p n (car l)))
(seq 0 (length p))))
(permute (cdr l)))))
Either way, the result is as expected:
(permute '(1 2 3))
=> '((1 2 3) (2 1 3) (2 3 1) (1 3 2) (3 1 2) (3 2 1))
In Common Lisp, the function is named "mapcan" and it is sometimes used to combine filtering with mapping:
* (mapcan (lambda (n) (if (oddp n) (list (* n n)) '()))
'(0 1 2 3 4 5 6 7))
(1 9 25 49)
In Racket that would be:
> (append-map (lambda (n) (if (odd? n) (list (* n n)) '()))
(range 8))
'(1 9 25 49)
But it's better to do it this way:
> (filter-map (lambda (n) (and (odd? n) (* n n))) (range 8))
'(1 9 25 49)