返回地图或转换为地图?字数灵药

时间:2016-05-26 14:19:44

标签: elixir

研究Elixir中的运动字数统计问题。目标是返回一个包含句子中每个单词的字数的地图。即如果字符串"一条鱼两条鱼红色鱼蓝色鱼"输出应该是%{ "one" => 1 , "fish" => 4 , "two" => 1 , "red" => 1 , "blue" => 1 }

就我而言:

iex(14)> sentence = "one fish two fish red fish blue fish"
"one fish two fish red fish blue fish"
iex(15)> String.split(sentence)                                                                         
["one", "fish", "two", "fish", "red", "fish", "blue", "fish"]
iex(16)> String.split(sentence) |> Enum.group_by(fn(x) -> x end)
%{"blue" => ["blue"], "fish" => ["fish", "fish", "fish", "fish"],
  "one" => ["one"], "red" => ["red"], "two" => ["two"]}

如何迭代此地图并对值运行Enum.count?我尝试了Enum.map(fn {k, v} -> {k, Enum.count(v)} end),但返回了元组[{"blue", 1}, {"fish", 4}, {"one", 1}, {"red", 1}, {"two", 1}]的列表。我是否需要将元组转换为映射,还是有更好的方法?如果我需要将元组转换为地图类型,我该怎么做?

我是Elixir和Erlang的新手,所以如果有人能告诉我为什么当你将地图传递给Enum.map函数时,你会得到一个元组列表而不是一个有用的地图。

2 个答案:

答案 0 :(得分:6)

您可以使用Enum.into/2转换成对列表(包含2个元素的元组):

[{"blue", 1}, {"fish", 4}, {"one", 1}, {"red", 1}, {"two", 1}] |> Enum.into(%{})

您可以Enum.reduce/3进入新地图,以防止额外的枚举:

String.split(sentence)
|> Enum.group_by(fn(x) -> x end)
|> Enum.reduce(%{}, fn {k, v}, acc -> Map.put(acc, k, Enum.count(v)) end)

地图在Enumerable协议的实现中明确转换为对的列表:https://github.com/elixir-lang/elixir/blob/v1.1.1/lib/elixir/lib/enum.ex#L2619

您可以使用Enum.reduce和Map.update/4一次性计算列表中的单词:

String.split(sentence)
|> Enum.reduce(%{}, fn word, acc -> Map.update(acc, word, 1, &(&1 + 1)) end)

答案 1 :(得分:0)

注意:有了elixir-1.10,您可以利用Enum.frequencies功能。

"one fish two fish red fish blue fish" 
|> String.split(" ")
|> Enum.frequencies

这样,您就可以使用管道操作器?