6

Haskell を学び、より関数的な方法で考える方法を学ぶことにしたので、このパラダイムで適切なアプローチを使用しようとする非常に単純な演習を解決しようとしています。

私はHaskellでこの簡単な演習を達成しようとしています:

Input: [2, 4, 1, 1, 2]
Output: [True, True, False, False, False, False, True, False, True, True]

したがって、リスト内の要素はInputリストFalse内に Output収まり、奇数の要素はTrue;になります。Inputそれぞれ、リストの値が示す回数だけ繰り返されます。

Inputリストをトラバースし、 i  ᵗʰ アイテムがペアの位置にある場合は、出力にTrue i回 to を追加しますOutputi  ᵗʰ アイテムが奇数の位置にある場合 、リストにFalse i回追加しますOutput

これは非常に単純な問題のように見えますが、実際にそうです。しかし、関数型プログラミングのバックグラウンドがない私には、Haskell でそれを表現する方法がわかりません。

リスト内包表記内で λ 関数を使用して、現在のインデックスを追跡しようとしました。

    row :: [Integer] -> [Bool]
    row xs = [ (last $ zipWith (\i x -> x) [1..] [0..i]) `mod` 2 == 0
                | j <- xs, i <- [0..j-1] ]

しかし、私はその動作を理解していないのでfindIndices 、簡単な代替手段として使用を終了しました:

    row :: [Integer] -> [Bool]
    row xs = [ (head $ findIndices (==j) (xs)) `mod` 2 == 0
                | j <- xs, i <- [0..j-1] ]

この最後のアプローチを使用すると、問題ないようです。

    > let xs = [ 1, 4, 3, 2 ]
    > print $ row xs
    [True,False,False,False,False,True,True,True,False,False]

しかし、アイテムは必ずしも一意ではないため、問題は解決されていません。

    > let xs = [ 2, 2, 4, 3]
    > print $ row xs
    [True,True,True,True,True,True,True,True,False,False,False]

head findIndices最初の出現のみを与えるためです。(私が思うに、うまくいったとしても、それはこの問題を解決するための非常に効率的な方法ではありません。)

Haskellyの方法で探している結果を得るにはどうすればよいですか?

4

6 に答える 6

11

Bool入力リストの各要素を要素が示す数の等しいs のシーケンスに変換したい場合、入力リストの数値のインデックスが偶数の場合、およびインデックスが奇数の場合はBoolbe が必要です。TrueFalse

そのためには、インデックスは必要ありません。インデックスは避けたほうがよいでしょう。これにより、よりシンプルで通常はより効率的なコードが得られます。ポイントは、値が交互に変化するということで、周期的なパターンを持っています。このような周期的なパターンを構築するために、Prelude は便利な機能を提供します。

cycle :: [a] -> [a]

Prelude> take 10 $ cycle [1,2,3]
[1,2,3,1,2,3,1,2,3,1]
Prelude> take 10 $ cycle [True,False]
[True,False,True,False,True,False,True,False,True,False]

ニート、それはまさに私たちが必要としているものです。

これで、入力リストの各要素を対応する とペアにすることができますBool:

[  2,    2,   4,   3]
[True,False,True,False,...

を使用zipしてペアを作成[(2,True), (2,False), ...]し、そのペアを適切な s のシーケンスに変換する関数を使用できますBool

しかし、そのパターンは非常に一般的であるため、そのための特別な高階関数zipWith.

したがって、リスト要素のタイプが の場合、次のIntように書くことができます

row :: [Int] -> [Bool]
row xs = concat $ zipWith replicate xs (cycle [True,False])

type のInteger場合、 は使用できませんが、 fromreplicateは使用できます。genericReplicateData.List

于 2013-05-31T21:43:43.923 に答える
2

zip要素とそのインデックスをペアにするために使用できることはすでにわかっているようです。各 indexiと対応する elementに対して、ブール値のコピーnを生成する必要があります ( を使用)。このブール値は、が奇数か偶数かによって異なります。これは、各タプルをブール値のリストに ping することを意味するため、リストのリストを取得します ( )。最後のステップは、これらのリストを とマージすることです (これは と組み合わせることができます) 。nreplicateimap(i, n)[[Bool]]concatmapconcatMap

row = concatMap (\(i, n) -> replicate n (odd i)) . zip [1..]

または、無意味なスタイルが気に入らない場合:

row xs = concatMap (\(i, n) -> replicate n (odd i)) (zip [1..] xs)
于 2013-05-31T21:25:43.793 に答える
1

別の解決策

row :: [Integer] -> [Bool]
row ns = r' True ns
    where
        r' :: Bool -> [Integer] -> [Bool]
        r' b (n:ns) = replicate b n : r' (not b) ns
        r' b   []   = []

(未検証)

于 2013-05-31T21:30:42.933 に答える
0

これが私がこれを行う方法です。

row [] = []
row xs = row' xs 0
   where row' xs i
            | i >= length xs    = []
            | otherwise         = (take (xs !! i) (repeat (isOdd i))) ++ (row' xs (i+1))


isOdd n = n `rem` 2 == 1

しかし、このコンピューターにはテストするためのghcがありません。

于 2013-05-31T21:13:36.243 に答える
0

私は解釈します

入力リストをトラバースし、i ᵗʰ アイテムがペアの位置にある場合は、出力に True i 回追加して出力に追加します。i ᵗʰ 項目が奇数の位置にある場合は、出力リストに False を i 回追加します。

これを解釈するには2つの方法があります。「すべての要素について、i 番目の要素が偶数の場合、True を i 回返します。それ以外の場合、false を i 回返します」または「すべての要素について、(v :: Int) を含む i 番目の要素は True を v 回返します。 i が奇数の場合、i は偶数または v 回 False です。」2 番目はすでに満足のいく答えを持っているので、1 番目に答えます。

インデックスを参照するのが好きな人もいますが、この場合、インデックスについて心配する必要はありません。Boolトラバースした要素の数を数えなくても、 の数を判断できます。

accum f (x:[]) = [x]
accum f (x:xs) = (x):(map f (accum f xs))

この関数は、関数fとリストを受け取ります。最初の要素を除くすべての要素に適用さfれ、リストの末尾に再帰呼び出しが行われ、f残りの各要素に再び適用されます。結果は次のとおりです。

accum (+1) [1,1,1,1,1]
[2,3,4,5,6]

この関数+1は、2 番目の要素に 2 回、2 番目の要素に 3 回、というように適用されます。これを行うことができます:

accum (\x -> [head x] ++ x) $ map (\x -> [x]) [2, 4, 1, 1, 2]
[[2],[4,4],[1,1,1],[1,1,1,1],[2,2,2,2,2]]

まず、各要素を 1 つの項目を持つリストに変換します。上記のラムダを使用したweaccumは、head をリストに連結します。Boolさらなる操作なしで s に直接変換できるようになりました。

(map . map) odd $ accum (\x -> [head x] ++ x) $ map (\x -> [x]) [2, 4, 1, 1, 2]
[[False],[False,False],[True,True,True],[True,True,True,True],[False,False,False,False,False]]

あなたはそう単純[Bool]ではありません。最初に次の代わりに使用できることに注意してください。[[Bool]]concatconcatmapmap . map

map odd $ concat $ accum (\x -> [head x] ++ x) $ map (\x -> [x]) [2, 4, 1, 1, 2]
于 2013-06-01T04:45:21.017 に答える