2017-03-24 11 views
2

私は重複を含むリストを持っています。私は、リスト内の各項目のインスタンス数を数えたいと思います。私の計画されました:エリクシール:リストを減らしてカウントの出現をマップする(別の引数でマップ・キーに一致するパターン)

list 
|> Enum.reduce(%{}, fn 
    item, %{item => count}=acc -> %{acc | item => count + 1} 
    item, acc -> Map.put(acc, item, 1) 
end) 

しかし、これはエラーillegal use of variable item inside map key match, maps can only match on existing variable by using ^itemでコンパイルに失敗します。

最初のパターンをitem, %{^item => count}=accに変更しました。その時点で、エラーはunbound variable ^itemになりました。

ここで何をすべきかわかりません。私はそれが別のものに基づいて1つの引数に一致するパターンを作ることが可能であることを知っています(比較関数の1つのヘッドについてfn a, a -> trueのように)。私はガードでそれをやってみたが、Map.has_key?/2はガードに入れられない。私は一般的に地図上でのマッチングについて多くの質問を見つけましたが、一致する値が別の引数から来た場合はそうしないでください。

+0

何らかの理由であなたは 'Map.update/4'を使用しませんでしたか? 'list |> Enum.reduce(%{}、fn x、acc - > Map.update(acc、x、1、&(&1 + 1))end)'となります。 – Dogbert

+0

...私は明らかに私が持っていると思ったようにドキュメントを読まなかったので、明らかに。私はそれを受け入れることができるように答えてください。 –

答えて

10

マップ内のキーの値を変更すると、それはまだ存在しない場合挿入はMap.update/4はまったく同じものです。周波数を計算するには、デフォルトでは1だろうと更新は、fnは、ちょうど値(&(&1 + 1))に1を追加します。

iex(1)> [1, 2, :a, 2, :a, :b, :a] |> 
...(1)> Enum.reduce(%{}, fn x, acc -> Map.update(acc, x, 1, &(&1 + 1)) end) 
%{1 => 1, 2 => 2, :a => 3, :b => 1} 
0

質問を書いている間にこれを見つけました。私はそれを共有したいと思っていましたが、他の誰かがより洗練された解決策を持っていれば、彼らに歓迎されているでしょう:

私が見つけた最高の解決策は...内部的に引数の1つをカレーします。バインドされた、純粋に構文的な目的のためです。

list 
|> Enum.reduce(%{}, fn item, acc -> 
    f = fn %{item => count}=acc -> %{acc | item => count + 1} 
      acc when is_map(acc) -> Map.put(acc, item, 1) 
     end 
    f.(acc) 
    end) 
関連する問題