在JS中,我可以这样做:
function countIt(str){
let obj = {};
for(let i = 0; i < str.length; i++){
if(!obj[str[i]]){
obj[str[i]] = 1;
} else {
obj[str[i]]++;
}
}
return obj;
}
console.log(countIt("hello"));
//returns {
e: 1,
h: 1,
l: 2,
o: 1
}
考虑到其不变性,在Elixir中用Map
计算每个角色的出现次数的最佳方法是什么?函数式语言解决此类问题的一般策略是什么?
答案 0 :(得分:8)
函数式语言解决此类问题的一般策略是什么?
<强> Enum.reduce/3
强>
"Hello World"
|> String.graphemes()
|> Enum.reduce(%{}, fn char, acc ->
Map.put(acc, char, (acc[char] || 0) + 1)
end)
#⇒ %{" " => 1, "H" => 1, "W" => 1, "d" => 1,
# "e" => 1, "l" => 3, "o" => 2, "r" => 1}
或(使用Map.update/4
信用@Dogbert:
"Hello World"
|> String.graphemes()
|> Enum.reduce(%{}, fn char, acc ->
Map.update(acc, char, 1, &(&1 + 1))
end)
或者,也许更惯用,基于模式匹配reducer参数来确定我们是否应该添加或启动计数器:
"Hello World"
|> String.graphemes()
|> Enum.reduce(%{}, fn char, acc ->
case acc do
%{^char => count} -> %{acc | char => count + 1}
_ -> Map.put(acc, char, 1)
end
end)
答案 1 :(得分:1)
使用Elixir-1.10
,您可以在一行中使用Enum.frequencies函数来完成此操作?
"Hello World" |> String.graphemes |> Enum.frequencies
答案 2 :(得分:0)
另一种可以实现此目的的方法是使用尾递归函数。此功能不再向堆栈添加任何帧,因为在运行期间,该功能将返回到自身的顶部而不是再次调用。为了实现这一点,你需要有一个累加器函数,如_count
。
defmodule Kitten do
def count(word) do
word
|> _count
end
defp _count("", acc), do: acc
defp _count(<<head::utf8, tail::binary>>, acc \\ %{}) do
updated_acc = Map.update(acc, <<head>>, 1, &(&1 + 1))
_count(tail, updated_acc)
end
end
答案 3 :(得分:0)
考虑到不可变性,使用Elixir中的Map计算每个字符出现的最佳方法是什么?函数式语言解决此类问题的一般策略是什么?
您可以使用Map.new/2并获得更简洁的代码:
count.exs :
defmodule Count do
def count_it(str) do
str
|> Map.new( &{<<&1 :: utf8>>,
Enum.count(str,fn x -> &1 == x end)}
)
end
end
使用进行测试:iex count.exs
iex(1)> Count.count_it('hello')
%{"e" => 1, "h" => 1, "l" => 2, "o" => 1}
iex(2)>