[racket] Is there a better way to do this in Racket?
Is there a better way to do this iin Racket (shorter, clearer, more readable)?
I have vectors of 1's and 0's (each vector representing a row of black
and white pixels. I need to transform each vector into a list of
pairs. Each pair containing the start and end vector-ref's of a
contiguous segment of black pixels.
Examples:
(list-of-ranges-of-ones #(0)) -> '()
(list-of-ranges-of-ones #(0 0)) -> '()
(list-of-ranges-of-ones #(0 0 0)) -> '()
(list-of-ranges-of-ones #(1)) -> '((0 0))
(list-of-ranges-of-ones #(1 1)) -> '((0 1))
(list-of-ranges-of-ones #(1 1 1)) -> '((0 2))
(list-of-ranges-of-ones #(1 1 1 0)) -> '((0 2))
(list-of-ranges-of-ones #(0 1 1 1)) -> '((1 3))
(list-of-ranges-of-ones #(0 1 1 1 0)) -> '((1 3))
(list-of-ranges-of-ones #( 0 1 1 1 0 0 0 1 1 1 0)) -> '((1 3) (7 9))
(list-of-ranges-of-ones #( 1 1 1 1 0 0 0 1 1 1 1)) -> '((0 3) (7 10))
(list-of-ranges-of-ones #( 0 1 0 1 0 1 0 1 0 1 0)) ->'((1 1) (3 3) (5
5) (7 7) (9 9))
I've come up with the following but is there a better way to do this
in Racket (shorter, clearer, more elegant?)
#lang racket
(define (list-of-ranges-of-ones vectr)
(let-values ([(more? get-next)(sequence-generate (in-indexed vectr))])
(define (add-a-range-of-ones current-range)
(define-values (current-val vectr-ref) (get-next))
(cond
[(and (not (more?)) (= current-val 1)) (list (reverse (cons
vectr-ref current-range)))]
[(and (not (more?)) (= current-val 0)) (list (reverse (cons
(sub1 vectr-ref) current-range)))]
[(= current-val 1) (add-a-range-of-ones current-range)]
[else (cons (reverse (cons (sub1 vectr-ref) current-range))
(skip-zeroes))]))
(define (skip-zeroes)
(cond
[(not (more?)) '()]
[else (define-values (current-val vectr-ref) (get-next))
(cond
[(= current-val 0) (skip-zeroes)]
[else (add-a-range-of-ones (list vectr-ref))])]))
(if (= 1 (vector-ref vectr 0))
(add-a-range-of-ones '(0))
(skip-zeroes))))
Thanks,
Harry