compact-number-list

higepon さんの d:id:higepon:20080925:1222326246 をやってみました。

こういう問題です。

整列済みの number のリストがある。

'(1 3 4 5 6 12 13 15)

このようなリストで数が連続している部分は '(1 2 3) -> '(1 . 3) のように両端のみを書くような記法を導入する。

最初の例のリストであれば以下のようになる。

'(1 (3 . 6) (12 . 13) 15)

このようなリストの変換をするコードを書きたい。

http://d.hatena.ne.jp/higepon/20080925/1222326246

で、わたしの書いたコードがこちら。

(use srfi-1)

(define (compact-number-list lst)
  (define (consec? a b)
    (if (pair? a)
      (= (+ (cdr a) 1) b)
      (= (+ a 1) b)))
  (define (update-range a b)
    (if (pair? a)
      (cons (car a) b)
      (cons a b)))
  (let loop ((result (list (car lst)))
             (rest (cdr lst)))
    (if (null? rest)
      (reverse result)
      (let ((prev (car result))
            (now (car rest)))
        (loop (if (consec? prev now)
                (cons (update-range prev now) (cdr result))
                (cons now result))
              (cdr rest))))))

(define (expand-compacted-list lst)
  (append-map (lambda (x)
                (if (pair? x)
                  (iota (- (cdr x) (car x) (- 1)) (car x))
                  (list x)))
              lst))

(compact-number-list '(1 3 4 5 6 12 13 15))

(expand-compacted-list  (compact-number-list '(1 3 4 5 6 12 13 15)))

流れは higepon さんのと同じですが、if を loop の中に入れて、苦し紛れながらもスッキリさせてみました。

逆の expand もやってみましたけど、こちらは瞬殺。