假设:
data = [[1,2,3, ..., n],[1,2,3, ..., n],[1,2,3, ..., n], ...]
# List with N rows of equal length
我们如何获得行总和:[3,6,9, ..., x]
使用列表理解
答案 0 :(得分:3)
我想说,最可读的方式是:
data
|> Enum.zip()
|> Enum.map(fn {v1, v2} -> v1 + v2 end)
#⇒ [2, 4, 6, ..., x]
对于N
列表的情况,可以使用递归:
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]
事情是在Erlang / Elixir中,将解决方案扩展到输入列表的最简单方法是递归地将任何内容简化为单个参数的情况。 [可能]有很多方法可以重写上面的例子以便更好地进行优化,但我明确地以最明显的方式编写了它。
对于来自OO背景的人来说,更明显(但却是惯用错误的)方式是zip
和map
元组列表:
data
|> Enum.zip()
|> Enum.map(fn e -> e |> Tuple.to_list() |> Enum.reduce(&Kernel.+/2) end)
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
结果:
Compiling 2 files (.ex)
Generated ttl app
Settings:
duration: 1.0 s
## ListSumBench
[16:49:06] 1/2: mapper
[16:49:09] 2/2: ttler
Finished in 5.56 seconds
## ListSumBench
benchma iterations average time
mapper 50 50194.78 µs/op
ttler 10 223662.80 µs/op
Enum.sum
和Enum.reduce(&Kernel.+/2)
之间的差异无关紧要,但sum
稍微快一点(例如3%)。