Elixir:将列表列表转换为一个列表

Elixir: transforming list of lists into one list

假设我们有以下列表:

[[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]]

如何将其转换为一个列表,其中包含相应位置上每个元素的总和,以便最终结果为 [5, 10, 15, 20] ?

不太可能有更简洁的变体可用,但可以避免多次迭代列表并使用递归一次完成所有操作(不涉及元组和转换)。

transpose = fn 
  [[x | xs] | xss], fun -> 
    [[x | Enum.map(xss, &hd/1)] | fun.([xs | Enum.map(xss, &tl/1)], fun)]
  [[] | xss], fun -> fun.(xss, fun)
  [], _ -> []
end
#⇒ #Function<43.97283095/2 in :erl_eval.expr/5>

transpose.(lists, transpose)                                           
#⇒ [[1, 1, 1, 1, 1], [2, 2, 2, 2, 2], [3, 3, 3, 3, 3], [4, 4, 4, 4, 4]]

lists |> transpose.(transpose) |> Enum.map(&Enum.sum/1)
#⇒ [5, 10, 15, 20]

或者,甚至更简单,避免中间转置:

sum = fn 
  [[] | _], _ -> []
  xs, fun -> 
    [(xs |> Enum.map(&hd/1) |> Enum.sum()) |
      fun.(Enum.map(xs, &tl/1), fun)]
end

sum.(lists, sum)
#⇒ [5, 10, 15, 20]