[1,2,3,4,5] が与えられたとき [[1,2][2,3][3,4][4,5]] を返すような関数を定義せよ
http://valvallow.blogspot.com/2011/02/12345-12233445.html
これは、窓をガラガラっと動かしながらリストを覗く、という問題です。ようするに、こういう話(n = 3 の場合)。
1 2 3 4 5 6 7 8 9リストに窓を作るには、drop して take するのが簡単です。窓をガラガラっと動かすほうは、この問題の場合にはリストを作ることになっているので、unfold 系の高階関数を使えばよいでしょう。Scheme よりすっきり書けるので Haskell で書きます。
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
import Data.List (unfoldr)drop の引数が n-1 なのは、窓をガラガラっとする前と後で隙間が要素1つぶんだけ重なっているという問題だからです。
overlaps n ls = unfoldr (window n) ls
window :: Int -> [a] -> Maybe ([a], [a])
window 1 _ = Nothing
window _ [] = Nothing
window _ (x:[]) = Nothing
window n ls = Just (take n ls, drop (n-1) ls)
Scheme も SRFI-1 に
unfold
があるので、ほぼ同じように「窓をガラガラっ」(drop して take した window を unfold)という気分で書けます。Gaucheだと、リストの長さの制限がゆるいバージョンの take や drop が用意されているし(take*
と drop*
。util.list を使う)、(use util.list)結果として、podhmoの日記 と同じ答になりました。
(define (overlaps ls n)
(unfold exhaust? (take$ n) (drop$ (sub n)) ls))
(define (sub n) (max 1 (- n 1))
(define (exhaust? ls) (or (null? ls) (null? (cdr ls))))
(define (take$ n) (cut take* <> n))
(define (drop$ n) (cut drop* <> n))
そういえば、どうして Scheme の take や drop は、リストでなく整数が最後の引数になっているんだろう…?