我有一个可能包含重复项的列表。我想计算列表中每个项目的实例数。我的计划是:
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
。
我不知道该怎么做。我知道可以基于另一个模式匹配一个参数(如fn a, a -> true
中的一个比较函数的头部),但显然不是这种情况。我试着用守卫做这件事,但Map.has_key?/2
不能戴卫兵。我在这里发现了许多关于在地图上匹配的问题,但是当匹配的值来自另一个参数时,我没有这样做。
答案 0 :(得分:15)
修改Map中某个键的值并插入(如果它尚未存在)正是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}
答案 1 :(得分:0)
嗯,在写这个问题时发现了这一点。想我分享它,但如果其他人有更清洁的解决方案,他们欢迎它:
我发现的最佳解决方案是......在某种程度上内部讨论其中一个论点,以便它受到约束,纯粹出于语法目的。
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)