从地图求和值 - 长生不老药
Sum values from a map - elixir
我编写的代码似乎可以正常工作,但我不知道为什么。
上下文:一个项目有很多budget_items
,这些是我正在展示的项目预加载的。
根据 budget_items
的列表,我正在计算项目的全部预算如下:
def total_budget(budget_items) do
Enum.reduce(budget_items, fn item, acc ->
%{amount_in_cents: item.amount_in_cents + acc.amount_in_cents}
end)[:amount_in_cents]
|> value_in_euro()
end
def value_in_euro(amount_in_cents) do
amount_in_cents/100
|> :erlang.float_to_binary([decimals: 2])
end
结果有效,但我不知道acc
是做什么的,最后是如何工作的。
有人可以详细说明吗?
如果您让我重写您的代码以使其更具可读性,则相当于:
def total_budget(budget_items) do
Enum.reduce(budget_items, fn item, acc ->
%{amount_in_cents: item.amount_in_cents + acc.amount_in_cents}
end)
|> Map.get(:amount_in_cents)
|> value_in_euro()
end
你的问题的重要部分是 reduce 块。如果你看一下 Enum.reduce/2,你会看到:
The first element of the enumerable is used as the initial value of the accumulator
理解其工作原理的一种非常简单的方法是使用如下示例:
iex> l = [1, 2]
[1, 2]
iex> Enum.reduce(l, fn x, acc, -> IO.puts "X: #{x}; acc: #{acc}" end)
X: 2; acc: 1
:ok
从这里可以看出,它几乎是从第二个元素开始,使用第一个元素作为累加器。
因此,当您传入 budget_items
时,它会使用键 :amount_in_cents
构建一个映射,该键首先等于 [=14= 的总和] 来自 budget_items
中的前两项。该地图作为您的 acc
传递到下一次迭代。
对于下一次迭代(第三项),acc
是在第一次迭代中构建的地图,它只有 :amount_in_cents
键,它再次生成一个地图只有 :amount_in_cents
键等于来自第三个元素的 amount_in_cents
加上累加器中的那个,等于前两个元素的总和。它将作为下一次迭代的累加器传递,依此类推。
然后,当添加了所有项目的所有 :amount_in_cents
后,您将从最后一次迭代产生的映射中获取该值,并将其传递给 value_in_euro/1
。
所以,简而言之,acc
的作用是,它充当一个累加器,保留您从所有以前的迭代中传递的任何内容,以便您可以根据需要对每个人使用它来自您的枚举的项目。传递给 Enum.reduce
的匿名函数的结果将始终用作下一次迭代的累加器,最后一次迭代的结果将被“返回”
除了Enum.reduce/2
, in this case using a combination of Enum.map/1
and Enum.sum/1
的解释可以说是比较简单
[
%{amount_in_cents: 100},
%{amount_in_cents: 200},
%{amount_in_cents: 300}
]
|> Enum.map(fn item -> item.amount_in_cents end)
|> Enum.sum()
输出:
600
值得一提的是Enum.sum/1
uses Enum.reduce/3
internally.
我编写的代码似乎可以正常工作,但我不知道为什么。
上下文:一个项目有很多budget_items
,这些是我正在展示的项目预加载的。
根据 budget_items
的列表,我正在计算项目的全部预算如下:
def total_budget(budget_items) do
Enum.reduce(budget_items, fn item, acc ->
%{amount_in_cents: item.amount_in_cents + acc.amount_in_cents}
end)[:amount_in_cents]
|> value_in_euro()
end
def value_in_euro(amount_in_cents) do
amount_in_cents/100
|> :erlang.float_to_binary([decimals: 2])
end
结果有效,但我不知道acc
是做什么的,最后是如何工作的。
有人可以详细说明吗?
如果您让我重写您的代码以使其更具可读性,则相当于:
def total_budget(budget_items) do
Enum.reduce(budget_items, fn item, acc ->
%{amount_in_cents: item.amount_in_cents + acc.amount_in_cents}
end)
|> Map.get(:amount_in_cents)
|> value_in_euro()
end
你的问题的重要部分是 reduce 块。如果你看一下 Enum.reduce/2,你会看到:
The first element of the enumerable is used as the initial value of the accumulator
理解其工作原理的一种非常简单的方法是使用如下示例:
iex> l = [1, 2]
[1, 2]
iex> Enum.reduce(l, fn x, acc, -> IO.puts "X: #{x}; acc: #{acc}" end)
X: 2; acc: 1
:ok
从这里可以看出,它几乎是从第二个元素开始,使用第一个元素作为累加器。
因此,当您传入 budget_items
时,它会使用键 :amount_in_cents
构建一个映射,该键首先等于 [=14= 的总和] 来自 budget_items
中的前两项。该地图作为您的 acc
传递到下一次迭代。
对于下一次迭代(第三项),acc
是在第一次迭代中构建的地图,它只有 :amount_in_cents
键,它再次生成一个地图只有 :amount_in_cents
键等于来自第三个元素的 amount_in_cents
加上累加器中的那个,等于前两个元素的总和。它将作为下一次迭代的累加器传递,依此类推。
然后,当添加了所有项目的所有 :amount_in_cents
后,您将从最后一次迭代产生的映射中获取该值,并将其传递给 value_in_euro/1
。
所以,简而言之,acc
的作用是,它充当一个累加器,保留您从所有以前的迭代中传递的任何内容,以便您可以根据需要对每个人使用它来自您的枚举的项目。传递给 Enum.reduce
的匿名函数的结果将始终用作下一次迭代的累加器,最后一次迭代的结果将被“返回”
除了Enum.reduce/2
, in this case using a combination of Enum.map/1
and Enum.sum/1
的解释可以说是比较简单
[
%{amount_in_cents: 100},
%{amount_in_cents: 200},
%{amount_in_cents: 300}
]
|> Enum.map(fn item -> item.amount_in_cents end)
|> Enum.sum()
输出:
600
值得一提的是Enum.sum/1
uses Enum.reduce/3
internally.