Reputation: 1040
Given two lists and a third list which has values that map to the permutations of the first two, I would like to create a Map of list1's key, list2's key, and list3's value. How can I get list3's value at a certain index if I am inside the loop?
Using Enum.at
is not the correct solution for this, I understand - it will traverse the whole list on every iteration. And if I try [head | tail] = list3
, it looks like I can't just set list3 = tail
for the next loop.
list1 = [1,2]
list2 = [3,4]
list3 = 'wxyz'
Enum.each(list1), fn i ->
Enum.each(list2), fn j ->
# Would like to just chop off the first value of list3 and
# pass the tail into the next iteration
end
end
Upvotes: 2
Views: 1663
Reputation: 1621
As a longtime rubyist, throwing down .each
became about as natural as breathing for me. After writing Elixir for a while now, .each
has almost become a code smell for me- whenever I use it by reflex, I end up going back to remove it, because it leads to awkward Elixir code.
As mentioned in comments, a comprehension is idiomatic for "looping": if you don't mind traversing 3 times, the following works:
result = for i <- list1, j <- list2, do: {i, j}
|> Enum.zip(list3)
|> Enum.into(%{})
iex> result
%{{1, 3} => 119, {1, 4} => 120, {2, 3} => 121, {2, 4} => 122}
You may choose to write it as a full-fledged function instead, especially if your example was a simplification of something more complicated. The following functions only traverse list3
once:
defmodule MapLists do
def map_it(l1, l2, l3, acc \\ %{})
def map_it([], _l2, _l3, acc), do: acc
def map_it([h|t], list2, list3, acc) do
{res1, new_list_3} = do_map_it(h, list2, list3, %{})
new_acc = Map.merge(acc, res1)
map_it(t, list2, new_list_3, new_acc)
end
defp do_map_it(item, [], l3, acc), do: {acc, l3}
defp do_map_it(item, [h2|t2], [h3|t3], acc) do
new_acc = Map.put(acc, {item, h2}, h3)
do_map_it(item, t2, t3, new_acc)
end
end
and usage:
iex> MapLists.map_it([1,2],[3,4],'wxyz')
%{{1, 3} => 119, {1, 4} => 120, {2, 3} => 121, {2, 4} => 122}
Upvotes: 4