Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elixir reduce order of elements

Tags:

reduce

elixir

Trying to understand how Elixir does Enum.reduce, I plugged it into a puts to watch the ouput. I'm not clear on why it executes the second list element first, instead of the first, and then steps through all of the others independently.

iex (30)> Enum.reduce([1,2,3,4], &(IO.puts("a#{&1} b#{&2}")))
a2 b1
a3 bok
a4 bok

(The a and b are just there to validate order)

Looking at the source, I'm thinking that it translates into

:lists.foldl(&IO.puts("a#{&1} b#{&2}"), 1, [2,3,4])

yielding the same result.

where 1 is the initial accumulator, and if I'd given it a function that gave it something to accumulate it would say something interesting other than "bok".

Inverting those initial values strikes me as an odd behavior though. How should I be thinking about the Reduce implementation?

like image 693
Rick R Avatar asked Nov 17 '15 05:11

Rick R


2 Answers

You are using Enum.reduce/2 function. Which treats the first element of the list as the accumulator. Just type h Enum.reduce/2 in iex. You will get the following output

Invokes fun for each element in the collection passing that element and the
accumulator acc as arguments. fun's return value is stored in acc. The first
element of the collection is used as the initial value of acc. If you wish to
use another value for acc, use Enumerable.reduce/3. This function won't call
the specified function for enumerables that are 1-element long. Returns the
accumulator.

Note that since the first element of the enumerable is used as the initial
value of the accumulator, fun will only be executed n - 1 times where n is the
length of the enumerable.

Examples

┃ iex> Enum.reduce([1, 2, 3, 4], fn(x, acc) -> x * acc end)
┃ 24

The second paragraph should clarify your doubt

Note that since the first element of the enumerable is used as the initial value of the accumulator, fun will only be executed n - 1 times where n is the length of the enumerable.

like image 84
coderVishal Avatar answered Sep 28 '22 16:09

coderVishal


There are two Enum.reduce functions, Enum.reduce/2 and Enum.reduce/3. Enum.reduce/3 is the usual reduce function taking an enumerable, initial accumulator and reducing function. Enum.reduce/2 is very similar to /3 but skips the initial accumulator and instead takes the first element in the enumerable as accumulator, for lists it could be implemented as: def reduce([first|rest], fun), do: reduce(rest, first, fun).

like image 31
Eric Meadows-Jönsson Avatar answered Sep 28 '22 17:09

Eric Meadows-Jönsson