成为Elixir的新手我在理解模式匹配方面遇到了一些问题。
如果我有这样的Elixir数据结构:
list_with_maps = [%{"id" => 1, "name" => "a"}, %{"id" => 2, "name" => "b"}]
从中获取所有id字段的值的最佳方法是什么?
答案 0 :(得分:28)
您可以使用Enum.map/2
在列表上进行映射并返回IDEnum.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 ]) do
至def 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"}]}]