Irvin Bridge
Irvin Bridge

Reputation: 313

Dynamically expand list in Elixir

I'm creating map dynamically in a list comprehension and then I'm trying to append generated map in every iteration to a list.

Here is a code:

 result = []
 temp_map = %{}

 for n <- 1..number do
   temp_map = Map.put_new(temp_map, :title, Enum.at(titles, n))
   temp_map = Map.put_new(temp_map, :content, Enum.at(contents, n))

   result = result ++ [temp_map]
 end

But that code returns this:

[[%{contents: "cont-2", title: "tit-2"}], [%{contents: "cont-2", title: nil}]]

My idea is having these lists:

titles = ["title-1", "title-2"]
contents = ["content-1", "content-2"]

generate structure like this:

[%{title: "title-1", content: "content-1"}, %{title: "title-2", content: "content-2"}]

I just need something to append to list dynamically.

Upvotes: 1

Views: 865

Answers (3)

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121010

I will put the answer using the comprehension approach here:

for {t, c} <- Enum.zip(titles, contents),
  do: %{title: t, content: c}
#⇒ [
#  %{content: "content-1", title: "title-1"},
#  %{content: "content-2", title: "title-2"}
# ]

Upvotes: 1

ryanwinchester
ryanwinchester

Reputation: 12157

You can't use temporary variables in a comprehension (or elsewhere) like that because Elixir's immutability will give you unexpected results if you are not used to that.

Example

items = ["foo", "bar", "baz"]

i = 0

for item <- items do
  i = i + 1
  IO.puts i
end

will output

1
1
1

Solution:

I would try something like this (using Enum.zip/2):

titles = ["title-1", "title-2"]
contents = ["content-1", "content-2"]

result = 
  Enum.zip(titles, contents)
  |> Enum.map(fn {title, content} -> %{title: title, content: content} end)

example

Upvotes: 2

Jonas Dellinger
Jonas Dellinger

Reputation: 1364

Your thinking in an OOP-oriented way, a more functional and correct approach would be using Enum.zip/2 together with Enum.map/2

titles = ["title-1", "title-2"]
contents = ["content-1", "content-2"]

result = Enum.zip(titles, contents) 
  |> Enum.map(fn {title, content} -> %{title: title, content: content} end)

# result: 
# [%{content: "content-1", title: "title-1"},
#  %{content: "content-2", title: "title-2"}]

Upvotes: 1

Related Questions