Elixir从地图列表中获取信息

时间:2017-07-26 05:06:00

标签: elixir

我通过帖子contacts = [%{"John" => ["0724573977"]}, %{"Mary" => ["0724573111", "0744556778"]}]发送给我的这个结构基本上是一个联系人列表,每个联系人都是一个地图name => phone_numbers

我正在尝试列出包含所有电话号码的列表,忽略任何名称,只是一个数字列表:

a = [%{"1" => ["0724573977"]}, %{"2" => ["0724573111", "0744556778"]}]

p = Enum.reduce a, [], fn(contact, acc) ->
    for {_record_id, phones} <- contact do
        for phone <- phones do
            acc ++ phone
        end
    end
end

IO.inspect p

这个产生:[[[["0724573977"] | "0724573111"], [["0724573977"] | "0744556778"]]]这是奇怪但我不知道我做错了什么。

4 个答案:

答案 0 :(得分:5)

已经发布了许多正确的答案,但我认为我会发布我的首选解决方案:使用for和3 <-

iex(1)> contacts = [%{"1" => ["0724573977"]}, %{"2" => ["0724573111", "0744556778"]}]
[%{"1" => ["0724573977"]}, %{"2" => ["0724573111", "0744556778"]}]
iex(2)> for contact <- contacts, {_, phones} <- contact, phone <- phones, do: phone
["0724573977", "0724573111", "0744556778"]

(我特别不喜欢基于List.flatten/1的解决方案,因为如果最后一级数据是列表而不是字符串,它们将不会以相同的方式工作。这些函数会在任何深度处平展每个列表。这无关紧要对于这种特殊情况,因为你的最后一级数据是一个字符串列表。)

答案 1 :(得分:3)

要获得一个可能使用的数字列表:

contacts
|> Enum.map(&Map.values/1)
|> List.flatten
#⇒ ["0724573977", "0724573111", "0744556778"]

要用数字替换名称,可以在链的中间使用Enum.with_index

答案 2 :(得分:2)

更容易做到:

a
|> Enum.flat_map(&Map.to_list/1)
|> Enum.flat_map(a, fn {_record_id, phones} -> phones end)

您尝试过的代码的问题是for的每次迭代都会在新列表中生成一个元素,另外因为Elixir是不可变的,所以您实际上并没有更改acc正在创建的内容将每个电话号码附加到同一列表的元素,因此最终会得到意外的列表列表。

答案 3 :(得分:2)

这可能不是惯用的Elixir,因为我是该语言的新手,但这对我有用:

iex(11)> List.flatten(Enum.map(a, fn(x) -> Map.values(x) end))
["0724573977", "0724573111", "0744556778"]