say we have a simple data array:
[
[1,2,3,4,5],
[1,2,3,4,5],
[1,2,3,4,5],
[1,2,3,4,5],
]
How can we reduce this to a column sums: [4,8,12,16,20]
(ie sum each column).
Also, how can we extend same to an NxM sized array?
say we have a simple data array:
[
[1,2,3,4,5],
[1,2,3,4,5],
[1,2,3,4,5],
[1,2,3,4,5],
]
How can we reduce this to a column sums: [4,8,12,16,20]
(ie sum each column).
Also, how can we extend same to an NxM sized array?
The sum of each row is 14 which does not match with your example result, so I’m not sure what you want…
I think he’s summing columns not rows. @CharlesO what have you tried so far? What’s the motivating problem you’re trying to solve?
Total row
Adding a total row to report data
Report data comes as NxM array
If that’s true, I’d transpose and then sum each list.
oh that makes sense, totally did not think of that
You keep saying row, but surely you mean column? In what you presented, [1,2,3,4,5]
is a row, which sums to 15 every time. If you want to do [1+1+1+1, 2+2+2+2,...]
that’s fine, but that’s a column sum not a row.
you are correct, i have updated the question. I need column sums
At least from the most common point of view. Most of us consider matrices as lists of rows. Some might view them as list of columns because it fits better in the data model.
there is nothing built in for Transpose in Enum or List
Enum.zip(list)
should do it.
Enum.zip gives:[{1, 1, 1, 1}, {2, 2, 2, 2}, {3, 3, 3, 3}, {4, 4, 4, 4}, {5, 5, 5, 5}]
You need to make the tuples lists again after that.
Google’s first hit for transposing a list in Elixir was a thread in this forum:
Using the matrix library tensor which was made for these kinds of tasks:
iex> alias Tensor.Matrix
iex> matrix = Tensor.Matrix.new([
[1,2,3,4,5],
[1,2,3,4,5],
[1,2,3,4,5],
[1,2,3,4,5],
], 4, 5)
iex> matrix |> Matrix.transpose |> Enum.map(&Enum.sum/1)
[4,8,12,16,20]
And if you want to do other things with these two-dimensional structures as well, I’d suggest turning them into matrix structs as early as possible: A linked-list-of-lists is takes linear time to access elements, and needs special care to keep the invariant of a matrix intact that all rows are the same length.
“Just for giggles”
defmodule Demo do
def sum_list_columns([]),
do: nil
def sum_list_columns([[] | _]),
do: nil
def sum_list_columns([[_ | _] | _] = data),
do: sum_list_columns(data, [], [0])
defp sum_list_columns([], [[] | _], sums),
do: :lists.reverse(sums)
defp sum_list_columns([], [[_ | _] | _] = done_lists, sums),
do: sum_list_columns(done_lists, [], [0 | sums])
defp sum_list_columns([[head | tail] | more_lists], done_lists, [sum | rest]),
do: sum_list_columns(more_lists, [tail | done_lists], [sum + head | rest])
end
data = [
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5]
]
Demo.sum_list_columns(data)
|> inspect()
|> IO.puts()
$ elixir demo.exs
[4, 8, 12, 16, 20]
$
Or “refactored”:
defmodule Demo do
def show(value) do
value
|> inspect()
|> IO.puts()
end
def reduce_columns([], _, _),
do: nil
def reduce_columns([[] | _], _, _),
do: nil
def reduce_columns([[_ | _] | _] = data, id, fun),
do: reduce_columns(data, id, fun, [], [id])
defp reduce_columns([], _id, _fun, [[] | _], accs),
do: :lists.reverse(accs)
defp reduce_columns([], id, fun, [[_ | _] | _] = done_lists, accs),
do: reduce_columns(:lists.reverse(done_lists), id, fun, [], [id | accs])
defp reduce_columns([[head | tail] | more_lists], id, fun, done_lists, [acc | rest]),
do: reduce_columns(more_lists, id, fun, [tail | done_lists], [fun.(head, acc) | rest])
end
data = [
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5]
]
id_value = 0
data
|> Demo.reduce_columns(id_value, &Kernel.+/2)
|> Demo.show()
id_value = 1
data
|> Demo.reduce_columns(id_value, &Kernel.*/2)
|> Demo.show()
$ elixir demo.exs
[4, 8, 12, 16, 20]
[1, 16, 81, 256, 625]
$