faster `filter-split`

pull/2/head
Matthew Butterick 10 years ago
parent dcff7418bf
commit f8f1b9d485

@ -19,6 +19,7 @@
(define-values (head tail) (splitf-at others (compose1 not pred))) (define-values (head tail) (splitf-at others (compose1 not pred)))
(cons (append (or car-match null) head) (slicef-at tail pred force?))])) (cons (append (or car-match null) head) (slicef-at tail pred force?))]))
(define+provide/contract (slice-at xs len [force? #f]) (define+provide/contract (slice-at xs len [force? #f])
((list? (and/c integer? positive?)) (boolean?) . ->* . list-of-lists?) ((list? (and/c integer? positive?)) (boolean?) . ->* . list-of-lists?)
(cond (cond
@ -26,17 +27,20 @@
[(len . > . (length xs)) (if force? null (list xs))] [(len . > . (length xs)) (if force? null (list xs))]
[else (cons (take xs len) (slice-at (drop xs len) len force?))])) [else (cons (take xs len) (slice-at (drop xs len) len force?))]))
(define+provide/contract (filter-split xs split-test) (define+provide/contract (filter-split xs split-test)
(list? predicate/c . -> . list-of-lists?) (list? predicate/c . -> . list-of-lists?)
(let loop ([xs (trimf xs split-test)] [acc '()]) (define-values (last-list list-of-lists)
(if (empty? xs) (for/fold ([current-list empty][list-of-lists empty])
(reverse acc) ; because accumulation is happening backward ([x (in-list xs)])
(let-values ([(item rest) (if (split-test x)
;; drop matching elements from front (values empty (if (not (empty? current-list))
;; then split on nonmatching (cons (reverse current-list) list-of-lists)
;; = nonmatching item + other elements (which will start with matching) list-of-lists))
(splitf-at (dropf xs split-test) (compose1 not split-test))]) (values (cons x current-list) list-of-lists))))
(loop rest (cons item acc)))))) (reverse (if (not (empty? last-list))
(cons (reverse last-list) list-of-lists)
list-of-lists)))
(define+provide/contract (frequency-hash x) (define+provide/contract (frequency-hash x)

Loading…
Cancel
Save