Write a procedure (group-by f lst)
that splits the list lst
into
sublists. The sublist boundaries are determined by the value of (f x)
for each element x
in lst
. When the value changes, a new sublist
is started from that element. Values of (f x)
are compared by
equal?
.
Return a list of the groups, i.e. each group is a sublist in the main list.
(define (group-by f lst)
(if (null? lst) '()
(let ((first (car lst)))
(let loop ((lst (cdr lst))
(key (f first))
(group (list first))
(groups '()))
(if (null? lst)
(reverse (cons (reverse group) groups))
(let ((newkey (f (car lst))))
(if (equal? key newkey)
(loop (cdr lst) key
(cons (car lst) group)
groups)
(loop (cdr lst) newkey
(list (car lst))
(cons (reverse group) groups)))))))))
Credit: Lassi Kortela
(group-by even? (iota 10))
;; ==> ((0) (1) (2) (3) (4) (5) (6) (7) (8) (9))
(group-by odd? '(1 3 5 2 1 6 4 1 7))
;; ==> ((1 3 5) (2) (1) (6 4) (1 7))
(group-by string-length '("aa" "bb" "ccc" "dddd" "eeee" "ffff" "g" "h"))
;; ==> (("aa" "bb") ("ccc") ("dddd" "eeee" "ffff") ("g" "h"))
(group-by (lambda (i) (truncate-quotient i 3)) (iota 20))
;; ==> ((0 1 2) (3 4 5) (6 7 8) (9 10 11) (12 13 14) (15 16 17) (18 19))