# Iterating over a list with a certain condition (sorry, I am very new to functional programming)

Hello everyone,

I am new to elixir and had questions regarding iterating over a list using Enum.each(). I want to iterate over a list and append items that satisfy a certain condition to another list.

I provided the code below and commented using pseudocode on what I mean by this.

``````def test do
list = [1,2,3,4,5,6,7,8,9]
p1 = []
p2 = []
p3 = []
Enum.each(list, fn(i) ->
#if (i) is at index 0 or 2 add (i) to [p1]
#if (i) is at index 1 or 3 add (i) to [p2]
end)
end
``````

Is this possible to do using Enum.each() or is there another preferred way of doing such a problem?

Variables in Elixir are immutable, so you won’t be able to modify a list from `Enum.each/2` like you would in an imperative programming language like C or Java.

What you’re looking for can be achieved with `Enum.reduce/3` instead.

I recommend you go through the guides at Elixir School to get a little more familiar with Elixir and functional programming in general before you continue:

They also have a segment specifically for the `Enum` module:

2 Likes

Hello and welcome,

``````list = [1,2,3,4,5,6,7,8,9]

result = list
|> Enum.with_index()
|> Enum.reduce({[], [], []}, fn {el, i}, {p1, p2, p3} ->
cond do
i == 0 || i == 2 -> {[el | p1], p2, p3}
i == 1 || i == 3 -> {p1, [el | p2], p3}
true -> {p1, p2, [el | p3]}
end
end)

IO.inspect result
{[3, 1], [4, 2], [9, 8, 7, 6, 5]}
``````

You even can remove the ugly cond with

``````list
|> Enum.with_index()
|> Enum.reduce({[], [], []}, fn
{el, i}, {p1, p2, p3} when i == 0 or i == 2 ->
{[el | p1], p2, p3}
{el, i}, {p1, p2, p3} when i == 1 or i == 3 ->
{p1, [el | p2], p3}
{el, _}, {p1, p2, p3} ->
{p1, p2, [el | p3]}
end)
``````

As mentionned, You need to think differently

Mainly because of immutability, but also scope.

You might need to reverse list if needed.

1 Like

thanks!!

If you really only need special treatment for the first 4 elements of `list` then there’s no need to even iterate. You can do one pattern match and then build the p1 and p2.

``````iex(106)> list = [1,2,3,4,5,6,7,8,9]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
iex(107)> [p10, p21, p12, p23 | p3] = list
[1, 2, 3, 4, 5, 6, 7, 8, 9]
iex(108)> p1 = [p10, p12]
[1, 3]
iex(109)> p2 = [p21, p23]
[2, 4]
iex(110)> p3
[5, 6, 7, 8, 9]

``````
2 Likes

didnt even think of this, thanks!

Welcome to the world of Elixir! Without answering your question directly, I see where you are coming from. So let’s take a step back and explain immutability as you will need to understand that first before anything else.

A variable is a binding between a `name` and a `memory location`. By executing `echo \$name` the computer does actually `echo #memory_location_17458`

The code you have written assumes mutability. That is: you can change the value of a variable (=memory location). In many languages that can be done the way you wrote the function. But it has side effects.

Say `p1` is bound to `#memory_location_17458`. What if `function2()` runs at the same time and also puts values in variable `p1` (= `#memory_location_17458`)? Once `p1` returns the end result stored in `#memory_location_17458` , you are surprised to find numbers of `function1()` and `function2()` in your list! They both wrote to the same memory location.

Elixir is based on immutability. Once a memory location has a value, it can’t be changed. However, what we can do is store a new value in a new memory address and let name `p1` point to the new memory location! With one important fact: the new `p1` is only bound to the new memory location within the current function scope.

So in the example with two functions, here is some pseudo code, using curly braces to make the scopes easier to spot.

``````p1 = [ ]

execute function1(p1) -> { p1 = p1 + 3 }
execute function2(p1) -> { p1 = p1 + 8 }

echo p1
``````
• both receive p1 as `#memory_location_17458`.
• as soon as `function1()` changes the value of `p1` by adding ‘3’ to the list is does not change `#memory_location_17458` but it stores the new value in another memory address (say: `#memory_location_11111`) and points the `p1` in it’s own scope to the new address.
• if function2() now would look at ‘his’ `p1` it would still be `#memory_location_17458` which is an empty list.
• as soon as `function2()` changes the value of `p1` by adding ‘8’ is does not change `#memory_location_17458` but it it stores the new value in another memory address (say: `#memory_location_222222`) and points the `p1` in it’s own scope to the new address.

We now have 3 times the `p1` name bound to 3 different memory addresses.

The original `p1` in global scope bound to #memory_location_17458 which has `[ ]`
The `p1` in scope of function1 bound to #memory_location_11111 which has `[ 3 ]`
The `p1` in scope of function2 bound to #memory_location_22222 which has `[ 8 ]`

• When we print `p1` at the last line, we are in the same scope as the first time we created `p1` so it still references `#memory_location_17458` and prints `[ ]` cause that is the value of that memory address.

Every function can run at the same time as they will never(!!!) influence other variables (=memory address).

Conclusion
Keep reading about this until you understand it well. As understanding immutability is key to understanding Elixir. Once you understand how immutability works, start reading some blogs about tail recusion (the technique that makes `for-loops` in Elixir without influencing memory addresses ).

Hope this helps a bit. I will edit my post when the Elixir gods correct me

3 Likes
``````def test do
list = [1,2,3,4,5,6,7,8,9]
{first4, p3} = Enum.split(list, 4)
#if (i) is at index 0 or 2 add (i) to [p1]
p1 = Enum.take_every(first4, 2)
#if (i) is at index 1 or 3 add (i) to [p2]
p2 = Enum.drop_every(first4, 2)
end
``````

You need to unlearn loops.

The same but easier to understand (I think)

``````iex(106)> list = [1,2,3,4,5,6,7,8,9]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
iex(107)> [a, b, c, d | rest] = list
[1, 2, 3, 4, 5, 6, 7, 8, 9]
iex(108)> p1 = [a, c]
[1, 3]
iex(109)> p2 = [b, d]
[2, 4]
iex(110)> p3 = rest
[5, 6, 7, 8, 9]
``````
1 Like