リストの要素を、隣り合った同じ要素ごとにまとめる。
(define group (lambda (lis) (let loop ((l1 (cdr lis)) (l2 (list (car lis))) (l3 '())) (cond ((null? l1) (reverse (cons l2 l3))) ((eq? (car l1) (car l2)) (loop (cdr l1) (cons (car l1) l2) l3)) (else (loop (cdr l1) (list (car l1)) (cons l2 l3))))))) (print (group '(1 1 2 2 3 3 3))) (print (group '(a a b b b c c)))
takatoh@nightschool $ gosh group.scm ((1 1) (2 2) (3 3 3)) ((a a) (b b b) (c c))
「同じ要素」を得るための proc を渡せるようにしたもの。
(define group-by (lambda (proc lis) (let loop ((l1 (cdr lis)) (l2 (list (car lis))) (l3 '())) (cond ((null? l1) (reverse (cons (reverse l2) l3))) ((eq? (proc (car l1)) (proc (car l2))) (loop (cdr l1) (cons (car l1) l2) l3)) (else (loop (cdr l1) (list (car l1)) (cons (reverse l2) l3))))))) (for-each print (group-by car '((1 1) (1 2) (2 3) (2 4) (2 5))))
ひとつのリストにしてしまうと見難いので for-each でグループごとに出力してみた。
takatoh@nightschool $ gosh group-by.scm ((1 1) (1 2)) ((2 3) (2 4) (2 5))
[追記]
gauche.sequence モジュールの group-sequence を使うとおなじことが出来る。
gosh> (use gauche.sequence) #<undef> gosh> (group-sequence '(1 1 2 2 3 3 3)) ((1 1) (2 2) (3 3 3)) gosh> (group-sequence '(a a b b b c c)) ((a a) (b b b) (c c)) gosh> (for-each print (group-sequence '((1 1) (1 2) (2 3) (2 4) (2 5)) :key car)) ((1 1) (1 2)) ((2 3) (2 4) (2 5)) #<undef>