Split list into groups by comparator

Problem

I want to split a list into lists by predicate, the function accept two sequential elements of the list.

Solution

(define (collect p a)
  (let collect ((in  a)
                (out '())
                (res '()))
    (cond ((null? in)
            (reverse! res))
          ((and (pair? (cdr in))
                (p (car in) (cadr in)))
            (collect (cdr in)
                     (cons (car in) out)
                     res))
          (else
            (let ((out (reverse! (cons (car in) out))))
              (collect (cdr in)
                       '()
                       (cons out res)))))))

Credit: Nils M Holm (ref: collect.scm)

Usage

(collect eq? '(a a a b c c))
;; ==> ((a a a) (b) (c c))

(collect < '(1 2 3 3 4 5 4))
;; ==> ((1 2 3) (3 4 5) (4))

Back to the Scheme Cookbook