在Elixir中,如何遍历另一个循环中的列表?

时间:2015-10-16 13:45:04

标签: elixir

给定两个列表和第三个列表,其值具有映射到前两个列表的排列,我想创建一个list1的key,list2的键和list3的值的Map。如果我在循环中,如何在某个索引处获取list3的值?

使用Enum.at不是正确的解决方案,我明白 - 它将在每次迭代时遍历整个列表。如果我尝试[head | tail] = list3,看起来我不能只为下一个循环设置list3 = tail

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

1 个答案:

答案 0 :(得分:3)

作为一个长期的红宝石,放下.each变得和我呼吸一样自然。在写了Elixir一段时间之后,.each几乎成了我的代码气味 - 每当我通过反射使用它时,我最终会回去删除它,因为它会导致笨拙的Elixir代码。

正如评论中所提到的那样,理解是循环的#34;如果你不介意遍历3次,那么以下工作:

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}

您可以选择将其编写为完整功能,尤其是如果您的示例是对更复杂的事物的简化。以下函数仅遍历list3一次:

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

和用法:

iex> MapLists.map_it([1,2],[3,4],'wxyz')
%{{1, 3} => 119, {1, 4} => 120, {2, 3} => 121, {2, 4} => 122}