We can't find the internet
Attempting to reconnect
Something went wrong!
Hang in there while we get back on track
Update matching list items with Access.filter/1
almirsarajcic
Use Access.filter/1 to update only the list elements that match a predicate, without mapping and rebuilding the surrounding structure yourself.
order = %{
items: [
%{sku: "A", status: :pending, cents: 1_000},
%{sku: "B", status: :paid, cents: 2_000},
%{sku: "C", status: :pending, cents: 500}
]
}
update_in(
order,
[:items, Access.filter(&(&1.status == :pending)), :cents],
&div(&1 * 90, 100)
)
# => %{
# items: [
# %{sku: "A", status: :pending, cents: 900},
# %{sku: "B", status: :paid, cents: 2000},
# %{sku: "C", status: :pending, cents: 450}
# ]
# }
The predicate runs against every item in the list. Each match continues through the rest of the access path, so :cents is updated only for pending items. Non-matching elements and the enclosing map keep their original shape.
The same accessor works with get_in/2, get_and_update_in/3, and pop_in/2. If nothing matches, the structure is returned unchanged.
Access.filter/1 expects the value at that point in the path to be a list. It raises when it encounters another data type, so make optional or mixed-shape data explicit before traversing it.
copied to clipboard