Nate
Nate

Reputation: 53

How to count cumulative sum for a list in Elixir?

I have a list of groups:

[[10, 1], [11, 1], [13, 3], [15, 10]]

I need to calculate cumulative sum for them, to get:

[[10, 1], [11, 2], [13, 5], [15, 15]].

Been trying with Enum.reduce but I do not know yet how to return new list as an accumulator, should I take tail of the list to get the last group and take the last amount from it or there's a better way?

Upvotes: 3

Views: 1372

Answers (2)

PatNowak
PatNowak

Reputation: 5812

Maybe I didn't get your point, so I prepared two answers based on exactly what you need.

1. List of lists, second value is cumulative sum

Solution without Enum.scan proposed by Dogbert, which is awesome one.

 def map_cumulative_sum(list) do
  list
  |> do_map_cumulative_sum([], 0)
 end

defp do_map_cumulative_sum([], acc, _sum_y) do
  Enum.reverse(acc)
end

defp do_map_cumulative_sum([[x, y] | t], acc, sum_y) do
  sum_y = y + sum_y
  do_map_cumulative_sum(t, [ [ x, sum_y] | acc], sum_y)
end

2. Single list with result

In this case Enum.reduce will do the job.

You can use version with or without accumulator (accumulator in this case would be first element of your list):

list = [[10, 1], [11, 1], [13, 3], [15, 10]]

# reduce list of lists to one list, where 2nd value is cumulative sum
Enum.reduce(list, fn([x, y], [acc_x, acc_y]) -> [x, y + acc_y] end)
> [15, 15]

Version with explicit accumulator will just have [0, 0] as second argument for Enum.reduce:

Enum.reduce(list, [0, 0], fn([x, y], [acc_x, acc_y]) -> [x, y + acc_y] end)

Upvotes: 0

Dogbert
Dogbert

Reputation: 222358

This is the perfect use case for Enum.scan/2 since you want to collect the value of each reduction:

[[10, 1], [11, 1], [13, 3], [15, 10]]
|> Enum.scan(fn [a, b], [_c, d] ->
  [a, b + d]
end)
|> IO.inspect

Output:

[[10, 1], [11, 2], [13, 5], [15, 15]]

Upvotes: 8

Related Questions