When given a list, I have to split the list into lists that group together elements that are the same.
For example: '(37 37 39 38 38 39 38 40 40 38) has to result in '((37 37) (39 39) (38 38 38 38) (40 40))
Can anyone help me with this?
Here's one way to do it:
(define (group lst)
(let iter ((lst lst) (found null) (res null))
(if (null? lst) ; all done ...
(reverse res) ; ... return result (reversed)
(let ((c (car lst))) ; isolate first element
(if (member c found) ; already processed that
(iter (cdr lst) found res) ; just go on with the next
(iter (cdr lst) ; otherwise add this to found and create a list of as many elements ...
(cons c found) ; ... as found in the list to the current result ...
(cons (make-list (count (curry equal? c) lst) c) res))))))) ; ... and go on with the next
Testing
> (group '(37 37 39 38 38 39 38 40 40 37))
'((37 37 37) (39 39) (38 38 38) (40 40))
> (group '(37 37 39 38 38 39 38 40 40 38))
'((37 37) (39 39) (38 38 38 38) (40 40))
Related
This question already has answers here:
How to add in a list in racket
(6 answers)
Closed 6 months ago.
What is an elegant or idiomatic way to get the sum of a list of lists in Racket? (I am new to Racket).
Here's what I put together but it requires two functions, ideally it would only need one:
(define (count-reps-per-round lst)
#| a partial solution with recursion,
only adds the subtotal
of each list and returns a new list
|#
(cond
[(empty? lst) empty]
[else (cons (apply + (first lst))
(count-reps-per-round (rest lst)))]))
(define (reps-per-workout lst) ; would be nice to combine with above into one function
(apply + (count-reps-per-round lst)))
(define results `(
(28 25 34 18)
(22 21 30 20)
(19 16 24 16)
(18 17 20 19)))
(display(count-reps-per-round results)) ; (105 93 75 74)
(= (reps-per-workout results) 347) ; #t
I would also be interested in any solution that doesn't require nested lists.
There's nothing wrong with splitting a complex problem in multiple helper functions, in fact this is encouraged when doing functional programming. But also we're encouraged to reuse built-in procedures whenever possible, for example we can write the solution to your problem in a single line by carefully combining map and apply:
(define (reps-per-workout lst)
(apply + (map (lambda (sl) (apply + sl)) lst)))
It works as expected:
(define results
'((28 25 34 18)
(22 21 30 20)
(19 16 24 16)
(18 17 20 19)))
(reps-per-workout results)
=> 347
Not sure this is "idiomatic" or that it's the most efficient implementation -- but seems like a simple solution:
(define (nested-sum lst)
(cond
[(empty? lst) 0 ]
[(list? lst) (+ (nested-sum (first lst)) (nested-sum (rest lst)))]
[else lst]))
(writeln (nested-sum `((1 2 3) (4 5 6)))) ; 21
(writeln (nested-sum 10)) ; 10
(writeln (nested-sum `())) ; 0
; and even deeply nested:
(writeln (nested-sum `((1 2 3) (4 5 6) ((10 20))))) ; 51
(def coll [10 27 7 12])
Desired result is:
==> (10 37 44 56)
I tried:
(map #(+ % (next %)) coll)
with no success
reductions can do that:
(reductions + [10 27 7 12])
; → (10 37 44 56)
How would I write a function in Dr. Racket which consumes a list of numbers (all numbers are 25) and produces a new list of numbers with 50 added to each preceding element?
Here is my code so far:
(define (new-funct f lst)
(cond
[(empty? lst) empty]
[else (cons (f (first lst))
(new-funct f (rest lst)))]))
(define (make-addition m)
(lambda (n) (+ m n)))
(define add50 (make-addition 50))
If I type in:
(new-funct add50 (list 25 25 25 25 25))
My expected output is
(list 25 75 125 175 225)
To explain the output, the first element stays the same. Then, 50 is added to 25 to give 75. Then, 50 is added to 75 to give 125 and so on.
Instead of this output, I get:
(list 75 75 75 75 75)
How would I correct my code? Thanks.
I recommend using map to map over a range of the indices and add:
(define (agg-adder n lst)
(map
(λ (i x) (+ x (* n i)))
(range (length lst))
lst))
This will result in a new list where the elements are each x + (n * (index of x)) for each x in the original list.
I'm working with Scheme and want to do some simple programs. I created one in which the multiples of five are filtered out of a list. Now I want to write a boolean function in which it will tell me if a specific element is part of the filtered list! So if I write "8" it will say false, but "40" would say true. Thanks!
(define (multiple-of-5 some-integer)
(equal? (remainder some-integer 5) 0))
(filter multiple-of-5 '(2 5 8 20 25 27 32 40))
output so far:
(5 20 25 40)
How you produced the list (5 20 25 40) is irrelevant. Thus all your code is irrelevant to this question. Basically you want this:
(define some-list '(5 20 25 40)) ; doesn't matter how this came about
(find (lambda (e) (= e 8)) some-list) ; ==> #f
(find (lambda (e) (= e 40)) some-list) ; ==> 40 (thruthy)
Now find is defined in the SRFI-1 List library and it is voted into R7RS Large. I imagine you could make an abstraction more useful for your case like (exists? 40 some-list) that uses find or you can roll your own like in Torbio's answer.
You can implement a contains? recursive function which travels the list and checks if the input number is equal to the current list element. The condition to stop is if the list is empty or if it contains the number. Pretty self-explanatory.
(define (contains? l i)
(if (null? l) #f
(or (equal? (car l) i) (contains? (cdr l) i))))
(contains? (filter multiple-of-5 '(2 5 8 20 25 27 32 40)) 8) ; #f
(contains? (filter multiple-of-5 '(2 5 8 20 25 27 32 40)) 40) ; #t
To simplify my question:
why this works
(mapcan #'(lambda (l) (list '1 '2) ) '(a b))
and this doesn't
(mapcan #'(lambda (l) '(1 2) ) '(a b))
?
I have to write a function that substitutes an element through all elements of list D at all levels of a given list L, using Map Functions.
I tried using mapcan for this:
(defun subAll (l k d)
(cond
((and (atom l) (eq l k))
d)
((and (atom l) (not (eq l k)))
(cons l '()))
(t (cons
(mapcan #'(lambda (l) (subAll l k d)) l)
'()))))
but I get following results for these 2 inputs:
1.
(subAll '(1(2(3(4(5(6(7)))))) (2(3(4 7(4(4(4(4)))))))) '7 '(a b))
=> ((1(2(3(4(5(6(A B(4(4(4(4)))))))))) (2(3(4 A B(4(4(4(4)))))))))
2.
(subAll '(1 2 3 (4 2 (3 2 (2)))) '2 '(99 98))
=>Lisp stack overflow.
But if replace
((and (atom l) (eq l k)) d) with ((and (atom l) (eq l k)) (list 'a 'b)) it works for input 1. Also I`ve made my own function that just deconstructs a list and reconstructs it:
(defun lst(l)
(cond
((null l) nil)
(t (cons (car l) ( lst (cdr l))))))
and it work if a replace ((and (atom l) (eq l k)) d) with ((and (atom l) (eq l k)) (lst d)) for both of my inputs above.
=> ((1(2(3(4(5(6(A B)))))) (2(3(4 A B(4(4(4(4)))))))))
=> ((1 A B 3 (4 A B (3 A B (A B)))))
Does mapcan accept only a special kind of list? If anyone can explain to me why it does that or give another solution I would be grateful. ( I can't use any built in functions like list or append, only if I make my own append and list)
I am using GNU CLISP 2.49
Short answer:
mapcan is destructive.
As per the Hyperspec entry on quote,
"The consequences are undefined if literal objects (including quoted objects) are destructively modified."
The easiest way to fix this is not to use mapcan.
(defun subAll (l k d)
(cond
((and (atom l) (eq l k))
d)
((and (atom l) (not (eq l k)))
(cons l '()))
(t (cons
(loop for elem in l append (subAll elem k d))
'()))))
with that definition,
CL-USER> (suball '(1 2 3 (4 2 (3 2 (2)))) '2 '(99 98))
((1 99 98 3 (4 99 98 (3 99 98 (99 98)))))
CL-USER>
Long Answer:
Let me get some style issues out of the way first.
Please format your code properly. It'll make it easier to read, both for you and people trying to help you.
(defun subAll (l k d)
(cond
((and (atom l) (eq l k))
d)
((and (atom l) (not (eq l k)))
(cons l '()))
(t (cons
(mapcan #'(lambda (l) (subAll l k d)) l)
'()))))
Next, the standard naming style for Common Lisp is train-case. Also, (cons foo '()), (cons foo nil) and (list foo) are all equivalent. You may as well use the shortest one. (You also don't need to sharp-quote lambda forms, though it doesn't particularly hurt).
(defun sub-all (l k d)
(cond
((and (atom l) (eq l k))
d)
((atom l)
(list l))
(t (list (mapcan #'(lambda (l) (sub-all l k d)) l)))))
Lets take a look at what happens to your function as it runs during that stack overflow case.
; SLIME 2013-04-02
CL-USER> (defun sub-all (l k d)
(cond
((and (atom l) (eq l k))
d)
((atom l)
(list l))
(t (list (mapcan #'(lambda (l) (sub-all l k d)) l)))))
;Compiler warnings :
; In an anonymous lambda form inside SUB-ALL: Undefined function SUB-ALL
SUB-ALL
CL-USER> (trace sub-all)
NIL
CL-USER> (sub-all '(1 2 3 (4 2 (3 2 (2)))) '2 '(99 98))
0> Calling (SUB-ALL (1 2 3 (4 2 (3 2 (2)))) 2 (99 98))
1> Calling (SUB-ALL 1 2 (99 98))
<1 SUB-ALL returned (1)
1> Calling (SUB-ALL 2 2 (99 98))
<1 SUB-ALL returned (99 98)
1> Calling (SUB-ALL 3 2 (99 98))
<1 SUB-ALL returned (3)
1> Calling (SUB-ALL (4 2 (3 2 (2))) 2 (99 98 3))
2> Calling (SUB-ALL 4 2 (99 98 3))
<2 SUB-ALL returned (4)
2> Calling (SUB-ALL 2 2 (99 98 3))
<2 SUB-ALL returned (99 98 3)
2> Calling (SUB-ALL (3 2 (2)) 2 (99 98 3))
3> Calling (SUB-ALL 3 2 (99 98 3))
<3 SUB-ALL returned (3)
3> Calling (SUB-ALL 2 2 (99 98 3))
<3 SUB-ALL returned (99 98 3)
3> Calling (SUB-ALL (2) 2 (99 98 3))
4> Calling (SUB-ALL 2 2 (99 98 3))
<4 SUB-ALL returned (99 98 3)
<3 SUB-ALL returned ((99 98 3))
<2 SUB-ALL returned ((3 99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 (99 98 3 ...
You never actually get to see the critical mutation point, but you can see an earlier equivalent (notice that by the second "layer" of calls, d is (99 98 3), rather than the (99 98) that you passed in initially). At some point shortly after that, d becomes (99 98 3 (2)), at which point the loop goes infinite because you can find your target inside of your replacement. What I generally end up doing when I need mapcan is defining my own functional version.
(defun mappend (fn list)
(loop for elem in list
append (funcall fn elem)))
(defun sub-all (tree target replacement)
(cond
((and (atom tree) (eq tree target))
replacement)
((atom tree)
(list tree))
(t (list
(mappend
(lambda (sub)
(sub-all sub target replacement))
tree)))))
This also gets around the Undefined behavior for quoted lists. Specifically, with the above definition of mappend,
CL-USER> (mappend #'(lambda (l) '(1 2)) '(a b))
; in: MAPPEND #'(LAMBDA (L) '(1 2))
; #'(LAMBDA (L) '(1 2))
;
; caught STYLE-WARNING:
; The variable L is defined but never used.
;
; compilation unit finished
; caught 1 STYLE-WARNING condition
(1 2 1 2)
CL-USER> (mappend #'(lambda (l) (declare (ignore l)) '(1 2)) '(a b))
(1 2 1 2)
CL-USER>
Check out this answer (already linked by Joshua Taylor above) for more details.