この種のことを行うことは、リストのシーケンシャルな性質のために常に厄介です。リストは、「一致するアイテムの検索」や「リスト要素の特定の組み合わせを組み合わせて新しいリストを計算する」などの操作にはあまり適していません。それは本質的に非シーケンシャルです。
少し前に戻った場合、ここで本当にやりたいことはString
、リスト内の個別の番号ごとに、それに関連付けられているすべての番号を見つけて合計することです。これはData.Map
、Haskellの最も標準的なものがにあるKey-Valueスタイルのデータ構造に適しているように聞こえます。これにより、任意の値タイプと任意の順序付きキータイプ(つまり、のインスタンスOrd
)のKey-Valueマップが得られます。
したがって、リストからを構築するには、...で関数をMap
使用できます。この関数は、便利なことに、Key-Valueタプルのリストの形式で入力を期待します。だからあなたはこれを行うことができます...fromList
Data.Map
import qualified Data.Map as M
nameMap = M.fromList [("Mary", 10), ("John", 45), ("Bradley", 30), ("Mary", 15), ("John", 10)]
...しかし、それは良くありません。なぜなら、それらを直接挿入すると、数字を追加するのではなく上書きするからです。重複キーを挿入するときに値を組み合わせる方法を指定するために使用M.fromListWith
できます。通常、これを使用して、各キーの値のリストなどを作成するのが一般的です。
しかし、あなたの場合、目的の結果に直接スキップできます。
nameMap = M.fromListWith (+) [("Mary", 10), ("John", 45), ("Bradley", 30), ("Mary", 15), ("John", 10)]
これにより、新しい名前が見つかった場合は直接挿入されます。それ以外の場合は、重複する値(数値)が追加されます。必要に応じて、次を使用してタプルのリストに戻すことができますM.toList
。
namesList = M.toList $ M.fromListWith (+) [("Mary", 10), ("John", 45), ("Bradley", 30), ("Mary", 15), ("John", 10)]
これにより、の最終結果が得られ[("Bradley",30),("John",55),("Mary",25)]
ます。
しかし、名前/番号のコレクションでより多くのことをしたい場合は、完了するMap
までそれを保持する方が理にかなっているかもしれません。