[racket] Is there a better way to do this in Racket?

From: Michael W. (mwilber at uccs.edu)
Date: Sun May 13 17:13:49 EDT 2012

Here's my shot using generators. It's probably much slower than yours
due to all the continuation jumps. This way keeps all four states in
your "state machine" in one place.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(require racket/generator)
(define (list-of-ranges-of-ones v)
  (define vec (append (vector->list v) '(0)))
  (sequence->list
    (in-generator
     (for/fold ([in-ones? #f])
         ([elt (in-list vec)]
          [index (in-naturals)])
       (cond [(and (zero? elt) in-ones?) ; Stop! Yield the list
              (yield (list in-ones? (sub1 index)))
              #f]
             [(and (zero? elt) (not in-ones?)) ; Keep stopping
              #f]
             [(and (not (zero? elt)) in-ones?) ; Keep going
              in-ones?]
             [(and (not (zero? elt)) (not in-ones?)) ; Go! Save this spot.
              index])))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



On Sun, 13 May 2012 16:47:45 -0400, Harry Spier <vasishtha.spier at gmail.com> wrote:
> 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
> ____________________
>   Racket Users list:
>   http://lists.racket-lang.org/users

Posted on the users mailing list.