Если первый список упоминается позже как product
, latter
как price
, и проблема возникает, когда у последнего нет элемента с p_id
, соответствующего одному из элементов в первом, можно go с
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) шаблоне предложения внутренней функции совпадать и б) при .price
доступе, когда Enum.find/2
возвращает nil
.
Непростым решением было бы устранить обе проблемы, используя Access
вместо точечной нотации:
Enum.map(
products,
&Map.put(
&1,
:price,
# ⇓⇓⇓⇓⇓⇓⇓⇓ ⇓⇓⇓⇓⇓⇓⇓⇓
Enum.find(price, fn p -> p[:p_id] == &1.id end)[:price]
)
)
Другим способом было бы правильно найти элемент и обработать его соответствующим образом
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)
OTOH, если id
отсутствует в product
, оно поднимается KeyError
из-за &1.id
звонка. чтобы избежать этого, можно использовать последний код и добавить явное предложение приемника-все для обработки этого. Эта версия является лучшей с точки зрения надежности и подвержена ошибкам:
Enum.map(
products, fn
%{id: id} = product ->
product_price =
price
|> Enum.find(&match?(%{p_id: ^id}, &1))
|> case do
%{price: price} -> price
_ -> nil # no price presented
end
Map.put(product, :price, product_price)
product -> product # no id presented
end)
#⇒ [
# %{count: 1, id: 7, name: "A", price: "$10.00"},
# %{count: 1, id: 8, name: "B", price: nil},
# %{count: 0, name: "C"}
# ]