[英]Loop through a list of values, find matches in keys and sum matched values in Elixir
我正在学习 Elixir 并且我在解决这个简单问题时遇到了困难:
我有一个值列表:
my_list = ["a", "b", "c", "y", "z", "a", "e"]
我有一个 map:
my_map = %{"a" => -1, "b" => 0, "c" => 1, "d" => 2, "e" => 3}
我想遍历my_list
,在 my_map 中找到所有关键事件,如果发生,则对my_map
中的值my_map
。
在上面的示例中,它应该返回 2,因为:
-1 + 0 + 1 + (ignored) + (ignored) - 1 + 3
# => 2
在具有可变变量的语言中,这是一件非常容易做到的事情(我们可以循环列表并添加一个计数器)。 我正在努力改变我的心态。
谢谢你的帮助!
我正在努力改变我的心态。
令人钦佩。 如果您愿意改变思维方式并尝试更实用地思考,您会在 Elixir 中获得巨大成功。 考虑到这一点,让我们分解问题。
我想遍历
my_list
更准确地说,您想对列表中的每个元素执行某些操作并获得结果列表。 那是Enum.map/2
。
Enum.map(my_list, fn x -> ...)
现在, ...
需要替换为我们想要对每个列表元素执行的操作。 我们要获取对应的 map 个元素,忽略那些不存在的。 由于我们要求和,“忽略”实际上只是意味着“替换为零”。 Map.get/3
可以从 map 获取一个值,如果没有提供则使用默认值。
Enum.map(my_list, fn x -> Map.get(my_map, x, 0) end)
现在,我们有一个数字列表。 我们只想要总和。 这可以根据Enum.reduce/3
来完成,但求和是一项足够常见的任务,它有自己的 function: Enum.sum/1
。
Enum.sum(Enum.map(my_list, fn x -> Map.get(my_map, x, 0) end))
最后,这是倒着读的。 它说“对列表映射的结果求和”,当它读起来更清晰时“获取列表,从 map 中获取元素,然后求和”。 我们可以用pipe 接线员清理它。 下面的和上面的是等价的。
my_list |> Enum.map(fn x -> Map.get(my_map, x, 0) end) |> Enum.sum
这是一个很好的理解用例:
for key <- my_list, val = my_map[key], reduce: 0 do
acc -> acc + val
end
这里的val = my_map[key]
是一个过滤器。 当key
不在my_map
中时,结果将为nil
,这是一个虚假值,因此被跳过。
虽然这里给出的两个答案都是完全有效的,但为了完整起见,我将使用普通递归发布另一个答案。
defmodule Summer do
def consume(list, map, acc \\ 0) # head
def consume([], _, acc), do: acc # exhausted
def consume([h | t], map, acc) when is_map_key(map, h),
do: consume(t, map, acc + Map.fetch!(map, h))
def consume([_h | t], map, acc), do: consume(t, map, acc)
end
Summer.consume my_list, my_map
#⇒ 2
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.