使用Enum.find_value合并地图列表

问题描述 投票:0回答:1

用于基于ID合并列表

products =
  [
    %{id: 7, name: "A", count: 1},
    %{id: 8, name: "B", count: 1},
    %{name: "C", count: 0}
  ]

price =
  [
    %{price: "$10.00", p_id: 7},
    %{price: "$29.95", p_id: 10},
  ]

当前正在使用

Enum.map(products, &Map.put(&1, :price, Enum.find(price, fn %{p_id: pid} -> pid == &1.id end).price))

但是如果产品列表中没有id,则会引发错误。

(KeyError) key :id not found in: %{count: 1, name: "A"} 

如何使用Enum.find_value

elixir
1个回答
0
投票

[如果将前一个列表稍后称为product,则将latter称为price,并且当后者没有与p_id对应的元素对应于前一个元素时,就会出现问题。

product =
  [
    %{id: 7, name: "A", count: 1},
    %{id: 8, name: "B", count: 1},
    %{id: 9, name: "C", count: 0}
  ]
price =
  [
    %{price: "$14.95", p_id: 8},
    %{price: "$10.00", p_id: 7}
  ]

在那种情况下,Enum.map/2会升高,但不会在Enum.find/2上升高,当找不到元素时会很高兴地返回nil,但是在a)内部函数子句模式匹配上并且b)在.price上访问时Enum.find/2返回nil

最讨厌的解决方案是使用Access代替点符号来消除这两个问题:

Access

另一种方法是正确查找元素并进行相应处理

Enum.map(
  products,
  &Map.put(
    &1,
    :price,
    #                        ⇓⇓⇓⇓⇓⇓⇓⇓              ⇓⇓⇓⇓⇓⇓⇓⇓
    Enum.find(price, fn p -> p[:p_id] == &1.id end)[:price]
  )
)

OTOH,如果Enum.map( products, fn %{id: id} = product -> product_price = price |> Enum.find(&match?(%{p_id: ^id}, &1)) |> case do %{price: price} -> price _ -> nil end Map.put(product, :price, product_price) end) 中不存在id,则由于调用product而将其升高KeyError。为了避免这种情况,可以使用后一种代码并添加显式的sink-all子句来处理此问题。就健壮性和易于出错而言,此版本是最好的:

&1.id
© www.soinside.com 2019 - 2024. All rights reserved.