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.
CodePudding user response:
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
CodePudding user response:
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 (l) (apply l)) 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