Life Goes On

まあまあだけど楽しんでる方です

ぷち・ぷろぐらむ

JAVA5.0でGO!! | プログラミングに自信があるやつこい!!
10分でコーディング | プログラミングに自信があるやつこい!!
via なんかしらんけど配る - * *scrap*
こういうのを Haskell で書くのはヒキョウだと思いつつ、書いてみたい誘惑に勝てませんでした。
布教活動の一環として公開します。
deal'(リストを n 個ずつに区切る)はProgramming:玉手箱:リストに、unfoldr を使ったきれいな書き方が載ってました。
もっと簡単に書けるよ、というのがあったら教えてください。

import Data.List

deal :: Int -> String -> [String]
deal n xs
    | null xs' = replicate n ""
    | otherwise = transpose xs'
    where xs' = deal' n xs
deal' n xs
    | length xs < n = []
    | otherwise = as : deal' n bs
    where (as,bs) = splitAt n xs

whoCanSee :: [String] -> [String] -> [String] -> [String]
whoCanSee users allowed report =
    map (users!!) $ findIndices (canSee report) allowed
    where canSee rs as = all (`elem` words as) rs

コメントいただいたので修正。length がリストの一部に対して何度も適用されてしまうので、再帰の外に出しました。これでリスト全体に対しては一度しか適用されないはず。
あと deal' は splits に名前を変更。

deal n xs
    | null xs' = replicate n []
    | otherwise = transpose xs'
    where xs' = takeWhile ((==n).length) $ splits n xs

splits n [] = []
splits n xs = as : splits n bs
    where (as,bs) = splitAt n xs

それから、関数 deal の中での場合分けが冗長に感じたので、以下のようにまとめてみたのですが、これは逆に分かりにくいですね。難読化してるだけだ。(Maybe 版に合わせて微修正)

dealL n = map concat . transpose
    . takeWhile ((==n).length) . splits n
    . (replicate n [] ++) . map (:[])

[1..100]>>=pen さんに「それ Maybe でもできるよ」って教えてもらいました。あぁ、この方が目的に適った使い方で分かりやすいかも。上の List 版と比べてもらうと、同じところ違うところがはっきりすると思います。init は悔しいので使わない。

dealM n = map catMaybes . transpose
    . takeWhile ((==n).length) . splits n
    . (replicate n Nothing ++) . map Just

と思ったら、one liner に進化してるし。