2

リストからいくつかの要素を削除したいと思います。これまでのところ、削除機能があります:

deleteElem :: Int -> [a] -> [a]
deleteElem _ [] = []
deleteElem x zs | x > 0 = take (x-1) zs ++ drop x zs
                | otherwise = zs

たとえば、要素のリストからリストに格納されている 2 つの位置を削除したいと思います。したがって、これはうまく機能します:

map (deleteElem 2) [["hello", "whatever", "foo", "bar"], ["hello", "whatever", "foo", "bar"], ["hello", "whatever", "foo", "bar"], [hello", "whatever", "foo", "bar"]]

結果が得られます:

[["hello", "whatever", "bar"], ["hello", "whatever", "bar"], ["hello", "whatever", "bar"], [hello", "whatever", "bar"]]

でも今は応募したいdeleteElem [2,3]

4

2 に答える 2

3

私があなたの質問を正しく解釈している場合、一度に 1 つのインデックスではなく、インデックスのリストに関数を適用する方法が必要だと言っています。

これを行う最も簡単な方法は、 deleteElems代わりに呼び出される別の関数を作成することですdeleteElem(末尾のs.)

deleteElemsタイプ[Int] -> [a] -> [a]になり、すべてのインデックスで呼び出されます。

注: 正しい解決策については、下部にある更新を参照してください (この部分はここに残しておきます。これにより、他の人が問題を解決しようとする最初の試みと、それがなぜ間違っているのかを学ぶことができます)。

これを行う1つの方法は次のとおりです。

deleteElems xs zs = foldr (\x z -> deleteElem x z) zs xs

これは次のように短縮できます。

deleteElems xs zs = foldr deleteElem zs xs

Prelude> deleteElems [2,3] [1..10]
[1,4,5,6,7,8,9,10]

またはあなたの例から:

Prelude> map (deleteElems [2,3]) [["hello", "whatever", "foo", "bar"], ["hello", "whatever", "foo", "bar"], ["hello", "whatever", "foo", "bar"], ["hello", "whatever", "foo", "bar"]]
[["hello","bar"],["hello","bar"],["hello","bar"],["hello","bar"]]

deleteElemsからのインデックスを削除するためfoldrに繰り返し呼び出すために使用します。の詳細な説明については、「foldr はどのように機能しますか?」を参照してください。.deleteElemxszsfoldr

アップデート:

コメントによると、上記の実装deleteElemsは実際には正しくありません。たとえば[2,4,6]、インデックスのリストが与えられると、最初に index2を削除4し、新しいリストを返し、次に新しいリストのインデックスを削除して新しいリストを返し、新しい6リストのインデックスを削除するためです。リスト。このプロセスは交換可能ではありません。つまり、インデックスの順序を変更したり、インデックスを指定したりしても、同じことは行われません。deleteElems[6,4,2]

関数 fromを使用して、予想される動作 (指定されたインデックスを元のリストから削除する)を取得する方法です。intersectData.List

deleteElems xs zs = foldr1 intersect $ map ($ zs) $ map deleteElem xs

この新しいバージョンのは、 の各インデックスを使用してdeleteElems適用され、特定の各インデックスにカリー化された関数のリストの数のリストを作成します。次に、はカリー化された各関数をに適用し、リストのリストを生成します。各内部リストは、インデックス および の 1 つに適用されます。最後に、fromを使用して、すべての正しい要素が削除されたリストを見つけます。deleteElemxslength xsdeleteElemmap ($ zs)deleteElemzsdeleteElemzsintersectData.List

また、チェックアウトすることをお勧めします どうやってfoldrが機能するのですか?.

于 2013-09-25T13:11:37.163 に答える
0

位置 i の要素を削除することを、位置 i でリストを分割し、リストの 2 番目の部分の先頭要素を除いてリストを再結合することと定義しましょう。とにかくこれはあなたが実装したものです。

ここで、複数の要素を削除することは、同じ手順を使用してリストの 2 番目の部分から要素を削除することと似ています。

これは、deleteElems の単純な定義を呼び出します。

deleteElems is = del [i-p | (p:i:_) <- tails $ sort $ 0:is] where
  del [] xs = xs
  del is xs = (r++) $ concatMap tail ss where
     (r:rs,ts) = unzip $ zipWith splitAt is $ xs:ts
     ss = filter (not . null) $ rs ++ [last ts]

ここで、リスト内包表記は、前のインデックスに関連するインデックスのリストを作成します。次にdel、 を使用zipWith splitAtして、指定された位置でリストを分割します。Notexs:tsは、すべての反復の「2 番目の部分」のリストを表し、 はすべての反復r:rsの「最初の部分」のリストです。明らかにr、最初の「最初の部分」であり、そのまま含まれています。残りは でトリミングされtailます。インデックスのリストで同じインデックスが複数回指定されている場合は、空のリストをフィルタリングする必要があります。

于 2013-09-25T22:25:48.980 に答える