从地图求和值 - 长生不老药

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.