我想计算字符串中出现的字数。实现是有问题的,但让我们用它来证明我的问题:
def count(sentence) do
words = String.split(sentence)
occurrences = Enum.map(words, fn w -> {w, Enum.count(words, &(&1 == w))} end)
Map.new(occurrences)
end
我想获得与上面相同的结果,但使用管道而不是中间结果变量:
def count(sentence) do
sentence
|> String.split
|> Enum.map(fn w -> {w, Enum.count(???)} end)
|> Map.new
end
是否可以在Enum.count函数中引用管道值?或者我必须使用中间变量吗?
答案 0 :(得分:9)
您可以在管道中放置一个匿名函数:
def count(sentence) do
sentence
|> String.split
|> (fn words -> Enum.map(words, fn w -> {w, Enum.count(words, &(&1 == w))} end) end).()
|> Map.new
end
iex(1)> count("foo bar baz foo")
%{"bar" => 1, "baz" => 1, "foo" => 2}
答案 1 :(得分:6)
虽然@ Dogbert的答案是完全正确的,但我会添加一个旁注:似乎只要你需要两次输出值,你就可能做错了。以上示例可能会重写为:
def count(sentence) do
sentence
|> String.split
|> Enum.reduce(%{}, fn e, acc ->
Map.put(acc, e, (Map.get(acc, e) || 0) + 1)
end)
end
或以其他许多方式减少所涉及的循环量(以及整个函数的 big-O )。
现代更新:从v1.8
开始,Kernel.SpecialForms.for/1
理解有reduce:
keyword parameter,这使得上述内容更容易掌握:
def count(sentence) do
for word <- String.split(sentence), reduce: %{} do
%{^word => count} = acc -> %{acc | word => count + 1}
acc -> Map.put(acc, word, 1)
end
end