Make group-by preserve the ordering of the original list.

This commit is contained in:
Vincent St-Amour 2014-05-21 16:10:21 -07:00
parent fbcada2045
commit 7abf555a8a
3 changed files with 26 additions and 19 deletions

View File

@ -162,22 +162,25 @@
;; groups together elements that are considered equal
;; =? should be reflexive, transitive and commutative
(define (group-by key l [=? equal?])
(for/fold ([res '()]) ; list of lists
([elt (in-list l)])
(let loop ([classes res] ; "zipper" of the equivalence classes
[rev-classes '()])
(cond [(null? classes)
;; did not find an equivalence class, create a new one
(cons (list elt) res)]
[(=? (key elt) (key (car (car classes))))
;; found the equivalence class
(append rev-classes ; we keep what we skipped
;; we extend the current class
(list (cons elt (car classes)))
(cdr classes))] ; and add the rest
[else ; keep going
(loop (cdr classes)
(cons (car classes) rev-classes))]))))
(define classes
(for/fold ([res '()]) ; list of lists
([elt (in-list l)])
(let loop ([classes res] ; "zipper" of the equivalence classes
[rev-classes '()])
(cond [(null? classes)
;; did not find an equivalence class, create a new one
(cons (list elt) res)]
[(=? (key elt) (key (car (car classes))))
;; found the equivalence class
(append rev-classes ; we keep what we skipped
;; we extend the current class
(list (cons elt (car classes)))
(cdr classes))] ; and add the rest
[else ; keep going
(loop (cdr classes)
(cons (car classes) rev-classes))]))))
;; reverse each class, so that group-by is stable
(map reverse classes))
;; (listof x) ... -> (listof (listof x))
(define (cartesian-product . ls)

View File

@ -167,7 +167,9 @@ for which @racket[pred] produces a true value.
(listof (listof A))]{
Groups the given list into equivalence classes, with equivalence being
determined by @racket[=?].
determined by @racket[=?]. Within each equivalence class, @racket[group-by]
preserves the ordering of the original list. The ordering of the equivalence
classes themselves is unspecified.
@examples[#:eval the-eval
(group-by (lambda (x) (modulo x 3)) '(1 2 1 2 54 2 5 43 7 2 643 1 2 0))

View File

@ -47,9 +47,11 @@
'(1 4 2 56 2 3)
(lambda (x y) (or (and (even? x) (even? y))
(and (odd? x) (odd? y)))))
'((2 56 2 4) (3 1)))
'((4 2 56 2) (1 3)))
(check-equal? (group-by car '((1 a) (4 b) (2 c) (56 d) (2 e) (3 f)))
'(((3 f)) ((56 d)) ((2 e) (2 c)) ((4 b)) ((1 a)))))
'(((3 f)) ((56 d)) ((2 c) (2 e)) ((4 b)) ((1 a))))
(check-equal? (group-by even? '(1 2 3 4 5 6))
'((2 4 6) (1 3 5))))
(test-suite "cartesian-product"
(check-equal? (cartesian-product '(1 2 3) '(a b c))
'((1 a) (1 b) (1 c)