在Elixir中生成运行总和或行总和
鉴于: 如何获得行和:在Elixir中生成运行总和或行总和,elixir,list-comprehension,Elixir,List Comprehension,鉴于: 如何获得行和:[3,6,9,…,x] 要使用哪个Enum函数,或者如何使用列表理解来保存一个运行总和,目前还不清楚。我想说,最可读的方法是: data = [[1,2,3, ..., n],[1,2,3, ..., n],[1,2,3, ..., n], ...] # List with N rows of equal length 对于N列表的情况,需要使用递归: data |> Enum.zip() |> Enum.map(fn {v1, v2} -> v1
[3,6,9,…,x]
要使用哪个
Enum
函数,或者如何使用列表理解来保存一个运行总和,目前还不清楚。我想说,最可读的方法是:
data = [[1,2,3, ..., n],[1,2,3, ..., n],[1,2,3, ..., n], ...]
# List with N rows of equal length
对于
N
列表的情况,需要使用递归:
data
|> Enum.zip()
|> Enum.map(fn {v1, v2} -> v1 + v2 end)
#⇒ [2, 4, 6, ..., x]
在Erlang/Elixir中,将解决方案扩展到输入列表的最简单方法是递归地将任何内容简化为单个参数的情况。有[可能]许多方法可以重写上面的示例以更好地优化,但我明确地以最明显的方式编写了它
对于那些来自OO背景的人来说,更明显(但习惯上是错误的)方法是将
zip
和map
元组映射到列表:
data = [[1,2,3],[1,2,3],[1,2,3]]
defmodule ListSum do
def mapper([inner1 | [inner2 | rest]]) do
reduced = inner1
|> Enum.zip(inner2)
|> Enum.map(fn {v1, v2} -> v1 + v2 end)
mapper([reduced | rest])
end
def mapper([list]) when is_list(list), do: list
end
IO.inspect ListSum.mapper(data)
#⇒ [3, 6, 9]
基准: 结果:
defmodule ListSum do
def mapper([inner1 | [inner2 | rest]]) do
reduced = inner1
|> Enum.zip(inner2)
|> Enum.map(fn {v1, v2} -> v1 + v2 end)
mapper([reduced | rest])
end
def mapper([list]) when is_list(list), do: list
def ttler(data) do
data
|> Enum.zip()
|> Enum.map(fn e -> e |> Tuple.to_list() |> Enum.sum() end)
end
end
defmodule ListSumBench do
use Benchfella
@list Enum.to_list(1..1_000)
@lists List.duplicate(@list, 1_000)
bench "mapper" do
ListSum.mapper @lists
end
bench "ttler" do
ListSum.ttler @lists
end
end
Enum.sum
和Enum.reduce(&Kernel.++/2)
之间的差异是微不足道的,但是sum
要快一点(比如3%)我想说,最可读的方法是:
data = [[1,2,3, ..., n],[1,2,3, ..., n],[1,2,3, ..., n], ...]
# List with N rows of equal length
对于
N
列表的情况,需要使用递归:
data
|> Enum.zip()
|> Enum.map(fn {v1, v2} -> v1 + v2 end)
#⇒ [2, 4, 6, ..., x]
在Erlang/Elixir中,将解决方案扩展到输入列表的最简单方法是递归地将任何内容简化为单个参数的情况。有[可能]许多方法可以重写上面的示例以更好地优化,但我明确地以最明显的方式编写了它
对于那些来自OO背景的人来说,更明显(但习惯上是错误的)方法是将
zip
和map
元组映射到列表:
data = [[1,2,3],[1,2,3],[1,2,3]]
defmodule ListSum do
def mapper([inner1 | [inner2 | rest]]) do
reduced = inner1
|> Enum.zip(inner2)
|> Enum.map(fn {v1, v2} -> v1 + v2 end)
mapper([reduced | rest])
end
def mapper([list]) when is_list(list), do: list
end
IO.inspect ListSum.mapper(data)
#⇒ [3, 6, 9]
基准: 结果:
defmodule ListSum do
def mapper([inner1 | [inner2 | rest]]) do
reduced = inner1
|> Enum.zip(inner2)
|> Enum.map(fn {v1, v2} -> v1 + v2 end)
mapper([reduced | rest])
end
def mapper([list]) when is_list(list), do: list
def ttler(data) do
data
|> Enum.zip()
|> Enum.map(fn e -> e |> Tuple.to_list() |> Enum.sum() end)
end
end
defmodule ListSumBench do
use Benchfella
@list Enum.to_list(1..1_000)
@lists List.duplicate(@list, 1_000)
bench "mapper" do
ListSum.mapper @lists
end
bench "ttler" do
ListSum.ttler @lists
end
end
Enum.sum
和Enum.reduce(&Kernel.++/2)
之间的差异是微不足道的,但是sum
要快一点(比如3%)问题在于:复制和重用代码很容易。。。但是理解它为什么有效,或者为什么这是一种显而易见的方式,并不是很清楚。我试图写一个描述性的“为什么”,但我有点不明白,这里什么是合适的措辞。我们有两个长度相同的列表,因此我想到了Enum.zip/2
。现在我们有了一个元组列表,因此Enum.map/2
。也许如果你在理解为什么会这样的过程中说明什么是一个阻碍因素,我可以更好地表达为什么。不,但我会更新N个列表的答案。为什么不只对N个列表这样做:|>Enum.zip |>Enum.map(fn t->t |>Tuple.to | u list |>Enum.sum end)
?@Dogbert根据基准,递归速度比元组快4.5倍。到\u list/1。问题是:复制和重用代码很容易。。。但是理解它为什么有效,或者为什么这是一种显而易见的方式,并不是很清楚。我试图写一个描述性的“为什么”,但我有点不明白,这里什么是合适的措辞。我们有两个长度相同的列表,因此我想到了Enum.zip/2
。现在我们有了一个元组列表,因此Enum.map/2
。也许如果你在理解为什么会这样的过程中说明什么是一个阻碍因素,我可以更好地表达为什么。不,但我会更新N个列表的答案。为什么不只对N个列表这样做:|>Enum.zip |>Enum.map(fn t->t |>Tuple.to | u list |>Enum.sum end)
?@Dogbert根据基准,递归比Tuple.to_list/1快4.5倍。