How to insert data in list inside for loop

Hi, I’m trying to insert data in a new list and found two problems.

Here is my example code

families = [41,42,43,44,45,46,47,48]

familyIds = []

Enum.each(families, fn family ->
    familyIds = [family | familyIds]
  end)

IO.inspect(familyIds)
  1. When I execute this it gave me like ’ ) ', ’ * ', ’ , ’ … .
    So I tried to put initial values in familyIds like [0] and then the first value got in the list but…

  2. The familyIds list didn’t updated. It was always [0]. Why is this happening?

So, is there a way not inserting intial value like [0] and work like [41, 42, 43 …] and
Is there a way updating familyIds at every loop?

Hello :wave:

In Elixir the variables are immutable, so you can’t iterate over it in order to append values.

if you want to concat to lists for example, you can go with something like

list_a = [1, 2, 3]
list_b = [4, 5, 6]
list_c = list_a ++ list_b = [1, 2, 3, 4, 5. 6]

While immutability sounds like a reasonable cause, this has nothing to do with immutability. Variables can be reassigned no problem without invalidating immutability (of values). The issue is the lexical scoping rules of elixir, which prevent (re-)assigning variables of an outer scope. Variables are only ever assigned for the current scope. In this case the anonymous function is the scope boundary.

fn family -> 
  familyIds = [family | familyIds]
end

This code accesses familyIds. The variable at this point is not present in the current lexical scope, so outer scopes are checked. familyIds = [] is found in the next outer scope. family is prepended to the []. The result is assigned for the variable familyIds within the scope of the anonymous function. The result is returned from the anonymous function (to be dropped by Enum.each). Then the code within the scope is completed and the scope variables are dropped. Enum.each calls the anonymous function with the next item and we start from the top.

5 Likes

There are no loops in Elixir, only expressions. Same with statements.

Really it’s both though. You could change the lexical scoping rules to allow rebinding in inner cases and it still won’t work because it’s a loop.

1 Like

Hi @menw,
this would be one of the ways to do it in Elixir.

families = [41,42,43,44,45,46,47,48]
family_ids = []

family_ids =
  Enum.reduce(families, family_ids, fn element, acc ->
    [element | acc]
  end)
  |> Enum.reverse()
4 Likes

Based on the previous reply, You could write it like this…

family_ids = [41,42,43,44,45,46,47,48] |> Enum.reduce([], & [&1 | &2]) |> Enum.reverse()

But given the operation, You could also have used a simpler way :slight_smile:

family_ids = [41,42,43,44,45,46,47,48]

and then, print it like this

family_ids |> IO.inspect(charlists: :as_list)                                                                              
[41, 42, 43, 44, 45, 46, 47, 48]
~c")*+,-./0"

IO.inspect() returns the value too, which is nice in a pipeline

2 Likes