【问题标题】:Pattern matching in a list of maps地图列表中的模式匹配
【发布时间】:2021-12-07 09:09:43
【问题描述】:

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

这是我的地图:

[
%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"}]

我会很感激你的帮助

【问题讨论】:

    标签: elixir pattern-matching ecto


    【解决方案1】:

    对于访问深度嵌套的数据,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))
    

    【讨论】:

      【解决方案2】:

      您提到了模式匹配。如果您正在寻找模式而不使用 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"
      

      当然,您可以将其分解为一个衬里,但我已为您分解,因此您可以了解流程。您可以像外科医生一样去获取越来越多的信息。听起来很奇怪,但问题在于简化它也会导致复杂化,所以请避免使用单一的表达方式。

      【讨论】:

      • 您当然可以编辑上述过程以将其用于结构。我用了一张地图。
      【解决方案3】:

      如果您的列表有正好 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"}]
      

      【讨论】:

        【解决方案4】:

        我认为您在这里不太需要模式匹配...Enum 模块提供了许多有用的工具来处理地图/列表等数据结构。

        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 -&gt; x = 匿名函数也被视为 &amp;(&amp;1)
        x.name == "map1" = 查找所需地图的条件。 \

        您可以通过运行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"
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-12-10
          • 2018-10-01
          • 2021-06-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-07-25
          相关资源
          最近更新 更多