使用Elixir在地图列表中获取特定键值?

时间:2015-12-29 10:18:21

标签: elixir

成为Elixir的新手我在理解模式匹配方面遇到了一些问题。

如果我有这样的Elixir数据结构:

list_with_maps = [%{"id" => 1, "name" => "a"}, %{"id" => 2, "name" => "b"}]

从中获取所有id字段的值的最佳方法是什么?

5 个答案:

答案 0 :(得分:28)

您可以使用Enum.map/2

在列表上进行映射并返回ID
Enum.map(list_with_maps, fn (x) -> x["id"] end)
[1, 2]

您可以使用capture运算符编写相同的函数:

Enum.map(list_with_maps, & &1["id"])

我更喜欢将& &1["id"]写为&(&1["id"]),但括号是可选的。

答案 1 :(得分:3)

获取Map密钥子集的更通用(且更简单)的方法是使用Map.take/2,您可以这样使用:

map = %{"id" => 1, "name" => "a"}
Map.take(map, ["id"])
> %{"id" => 1}

如您所见,它需要一组键并返回一个只包含您想要的键的新地图。

现在,将其应用于列表就像使用地图一样简单,然后在mapper函数中使用Map.take/2。正如已经指出的那样,你可以使用lambda:

来做到这一点
Enum.map(list_with_maps, fn (map) -> Map.take(map, ["id"]) end)

或者您可以使用捕获:

Enum.map(list_with_maps, &(Map.take(&1, ["id"])))

这将创建更多的中间地图,但对于大多数不会出现问题的情况,因为Elixir对内存重用非常聪明,实际上很多时候都不会创建这些对象,unles

答案 2 :(得分:2)

为了完整地回答这个问题的答案,你也可以这样做:

defmodule Test do
  def get_all_ids([head | tail ]) do
    IO.puts head["id"]
    get_all_ids(tail)
  end

  def get_all_ids([]) do
    IO.puts "end"
  end
end

将使用如下:

iex(7)> Test.get_all_ids(list_with_maps)
1
2
end
:ok

虽然我认为@ Gazler的答案在这种情况下是更好的答案。

哦,既然您特别提到了模式匹配,那么这也可行:

defmodule Test do
  def get_all_ids([%{"id" => id} = m  | tail ]) do
    IO.puts id
    get_all_ids(tail)
  end

  def get_all_ids([]) do
    IO.puts "end"
  end
end

电话会是完全一样的;第二种方法的不同之处在于,它使用模式匹配来解析参数列表中的映射。

您也可以更改此行中的参数列表:def get_all_ids([%{"id" => id} = m | tail ]) dodef get_all_ids([%{"id" => id} = _m | tail ]) do,以避免警告m未被使用。

答案 3 :(得分:2)

从地图列表中提取名称值

names = for %{name: n, id: _} <- list_with_maps, do: n

答案 4 :(得分:0)

另一种选择是使用get_in函数并利用Access模块。通过访问模块,您可以构建处理嵌套数据结构的表达方式。

要获取"id"处的值列表,可以运行:

get_in(list_with_maps, [Access.all, "id"])  

传递Access.all作为列表中的第一个元素,然后传递"id"告诉get_in返回所有list_with_maps的{​​{1}}值。

对于本示例来说,这似乎有些矫kill过正,但是如果您的结构看起来像这样:

"id"

我们可以使用以下所有名称:

list_with_maps = [%{"id" => 1, "identities" => [%{"name" => "a"}, %{"name" => "Secret A"}]}, %{"id" => 2, "identities" => [%{"name" => "b"},%{"name" => "Secret B"}]}]