文字列の均等分割
この問題は、除算だけでははく算術演算とか、文字列の長さをstrlenの類いで測るとかをしなくても、多分書けるのではないかと思います。
Posted feedbacks - Haskell
文字列分のTrueの後にFalseをいくつかくっつけたリストを作り、nで分割した後transposeして、Trueの分だけ先頭から切り出す。
例えばdivid 3 "abcdefghijk"なら
bools = [T,T,T,T,T,T,T,T,T,T,T,F,F,F]
slices = [[T,T,T],[T,T,T],[T,T,T],[T,T,F]]
transpose = [[T,T,T,T],[T,T,T,T],[T,T,T,F]]
boolsを無限リスト(Fが後ろに無限個付く)にしてもいけるかと思ったけど、無限リストのtransposeは止まらないみたい。そこまで見ないんだから止まってくれても良さそうな気がするけど…
例えばdivid 3 "abcdefghijk"なら
bools = [T,T,T,T,T,T,T,T,T,T,T,F,F,F]
slices = [[T,T,T],[T,T,T],[T,T,T],[T,T,F]]
transpose = [[T,T,T,T],[T,T,T,T],[T,T,T,F]]
boolsを無限リスト(Fが後ろに無限個付く)にしてもいけるかと思ったけど、無限リストのtransposeは止まらないみたい。そこまで見ないんだから止まってくれても良さそうな気がするけど…
1 2 3 4 5 6 7 8 9 10 11 12 13 | import Data.List
divid n cs = snd $ mapAccumL taker cs
$ transpose
$ slices
$ bools cs
where
slices xs | n > length xs = []
| otherwise = (take n xs):(slices $ drop n xs)
bools cs = (map (const True) cs) ++ (replicate n False)
taker (c:cs) (True:bs) = let (cs',frag) = (taker cs bs)
in (cs', c:frag)
taker cs _ = (cs, [])
|
いや、そもそも後ろにFalseをくっつける必要が無かった。takeはリストの方が短いと結果も短くしてくれるのね。(Gaucheのtake*の動作)
1 2 3 4 5 6 7 8 | import Data.List
divid n cs = snd $ mapAccumL taker cs $ transpose $ slices cs
where
slices [] = []
slices xs = (take n xs):(slices $ drop n xs)
taker cs [] = (cs, [])
taker (c:cs) (b:bs) = let (cs',frag) = (taker cs bs) in (cs', c:frag)
|
私の用意していたものはshiroさんの解と本質的に同じでした。 slices と taker にも汎用性がありそうなのでトップレベルでの定義にしてあります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import Data.List
import qualified System.IO.UTF8 as U
divid :: Int -> [a] -> [[a]]
divid n xs
= snd $ mapAccumL ((swap .) . flip splitWith) xs $ transpose $ slices n xs
swap :: (a,b) -> (b,a)
swap (x,y) = (y,x)
splitWith :: [b] -> [a] -> ([a],[a])
splitWith _ [] = ([],[])
splitWith [] xs = ([],xs)
splitWith (x:xs) (y:ys) = case splitWith xs ys of (zs,ws) -> (y:zs,ws)
slices :: Int -> [a] -> [[a]]
slices n = unfoldr phi
where
phi [] = Nothing
phi xs = Just $ splitAt n xs
|




nobsun
#4090()
Rating-1/3=-0.33
1 reply [ reply ]