地图列表中的模式匹配

Pattern matching in a list of maps

我有一个嵌套的地图列表,我想抓取地图的特定元素。我该怎么做?

这是我的地图:

[
%Eagle.Content.TemplateFields.TemplateField{
__meta__: #Ecto.Schema.Metadata<:loaded, "template_fields">,
id: 13,
inserted_at: ~N[2021-10-20 12:02:42],
name: "Meta title",
name_slug: "meta_title",
position: nil,
settings: %{"options" => [], "validate" => %{"required" => []}},
template: #Ecto.Association.NotLoaded<association :template is not loaded>,
template_id: 4,
type: "text",
updated_at: ~N[2021-10-20 12:02:42]
},
%Eagle.Content.TemplateFields.TemplateField{
__meta__: #Ecto.Schema.Metadata<:loaded, "template_fields">,
id: 14,
inserted_at: ~N[2021-10-20 12:02:42],
name: "Meta description",
name_slug: "meta_description",
position: nil,
settings: %{"options" => [], "validate" => []},
template: #Ecto.Association.NotLoaded<association :template is not loaded>,
template_id: 4,
type: "text",
updated_at: ~N[2021-10-20 12:02:42]
 }
]

我想从第二张地图上取名字。

现在我有这样的东西: x = landing_page.template.fields[%{name: "Meta description"}]

我将不胜感激

为了访问深度嵌套的数据,Access 模块有一些助手提供了一种解决方案:

get_in(landing_page.template.fields, [Access.at(1), :name])
#=> "Meta description"

或者,如果我误解了你的要求,而你正试图在列表中查找一个元素(并且不想更改你的数据库查询),Enum.find/3 可以成为你的朋友:

Enum.find(template_fields, fn field -> field.name == "Meta description" end)
# or if you prefer a matching syntax
Enum.find(template_fields, &match?(%{name: "Meta description"}, &1))

您提到了模式匹配。如果您正在寻找模式而不使用 Enum 等中的辅助函数,那么请执行:

[ a | b ] = your_value # your deeply nested data. You can ignore a or b using an _

[ c ] = b # which one you want, the first or second element from your map? I chose the second "b" from above.

v = c[:name] # the value of atom "name" in your deeply nested example. #=> "Meta description"

当然你可以把它分解成一个衬里,但我为你分解了,所以你得到了过程。你可以像外科医生一样去获取越来越多的信息。听起来很奇怪,问题是通过简化它也会导致复杂化所以避免一个线性表达式。

如果你的列表有正好 2个元素,那么你的模式匹配看起来像这样(名称被分配给捕获中的name变量) .这对简单映射和结构一样有效:

iex> [_, %{name: name}] = [%{name: "Foo"}, %{name: "Meta description"}]

iex> name
"Meta description"

如果您的列表可能有 2 个 或更多 个元素,那么您需要调整匹配的形状以包含一个 | 来表示其余的列表(如果存在):

iex> [_, %{name: name} | _] = [%{name: "Foo"}, %{name: "Meta description"}, %{name: "other stuff"}]

我认为你在这里不需要模式匹配...Enum 模块提供了一堆有用的工具来处理像 maps/lists.

这样的数据结构
list = [
 %{name: "map1", attribute: "this is my attribute"},
 %{name: "map2", attribute: "this is my other attribute"}
]
map = Enum.find(list, fn x -> x.name == "map1" end)

list = 地图列表
fn x -> x = 匿名函数也被视为 &(&1)
x.name == "map1" = 找到所需地图的条件。 \

您可以通过 运行ning iex -S mix

在您的混音控制台中 运行 此代码

我的输出在这里:

iex(1)> list = [
...(1)>  %{name: "map1", attribute: "this is my attribute"},
...(1)>  %{name: "map2", attribute: "this is my other attribute"}
...(1)> ]
[
  %{attribute: "this is my attribute", name: "map1"},
  %{attribute: "this is my other attribute", name: "map2"}
]
iex(2)> map = Enum.find(list, fn x -> x.name == "map1" end)
%{attribute: "this is my attribute", name: "map1"}
iex(3)> map.name
"map1"
iex(4)> map.attribute
"this is my attribute"