地图列表中的模式匹配
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"
我有一个嵌套的地图列表,我想抓取地图的特定元素。我该怎么做?
这是我的地图:
[
%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"