У меня есть вложенный словарь в эликсире, из которого я хочу сохранить последние элементы в новом словаре.
sorted_slides = [
%{
id: 1,
visual_events: [
%{entity_id: 1, payload: "abc"},
%{entity_id: 2, payload: "def"}
]
},
%{
id: 2,
visual_events: [
%{entity_id: 2, payload: "yui"},
%{entity_id: 3, payload: "def"},
%{entity_id: 4, payload: "ghi"},
]
},
%{
id: 3,
visual_events: [
%{entity_id: 2, payload: "ert"},
%{entity_id: 4, payload: "poi"},
]
}
]
dict = %{}
Enum.each(sorted_slides, fn slide ->
Enum.each(slide.visual_events, fn ve ->
eid = ve.entity_id
dict = Map.put(dict, eid, ve)
IO.inspect(dict)
end)
end)
IO.inspect(dict)
Моя исходная структура данных содержит элементы, которые могут быть перезаписаны более новыми элементами. Я хочу, чтобы новый dict
был:
dict = %{
1 => %{entity_id: 1, payload: "abc"},
2 => %{entity_id: 2, payload: "ert"},
3 => %{entity_id: 3, payload: "def"},
4 => %{entity_id: 4, payload: "poi"}
}
Я хочу, чтобы dict
сохранял изменения, внесенные в него каждой итерацией, но я думаю, что область видимости здесь работает иначе, чем в некоторых других языках.
Как мне добиться этого в Эликсире?
Если вы хотите построить структуру внутри «цикла», в большинстве случаев вы можете использовать Enum.reduce/3:
Enum.reduce(sorted_slides, %{}, fn slide, acc ->
Enum.into(slide.visual_events, acc, fn event ->
{event.entity_id, event}
end)
end)
Внутренний цикл также можно реализовать с помощью Enum.reduce/3
, но Enum.into/3 делает его немного более компактным.
Enum.each/2 предназначен только для выполнения побочных эффектов (например, печати), но не возвращает никакого фактического результата, он просто всегда возвращает :ok
.
Я предполагаю, что область видимости здесь работает иначе, чем в некоторых других языках.
Точно, в Эликсире вы не мутируете существующие структуры, вы создаете новые структуры и должны их передавать. Обычно это относится к нашему аккумулятору acc
выше.
Примечание: в Эликсире они называются не диктовками, а картами . В прошлом была устаревшая структура dicts .
Вы можете использовать Enum.flat_map/2 для извлечения внутренних элементов и Map.new/2 для создания новой карты из этих элементов. Map.new/2
гарантирует, что последний элемент будет преобладать при наличии повторяющихся ключей.
sorted_slides
|> Enum.flat_map(fn %{visual_events: items} -> items end)
|> Map.new(fn %{entity_id: id} = map -> {id, map} end)
Результат:
%{
1 => %{entity_id: 1, payload: "abc"},
2 => %{entity_id: 2, payload: "ert"},
3 => %{entity_id: 3, payload: "def"},
4 => %{entity_id: 4, payload: "poi"}
}
Может быть полезно продемонстрировать в коде, что вы должны переназначить результат этих операций, например.
modified_list = Enum.map(old_list, &some_func/1)
потому что, как вы указали, в Эликсире вы не можете видоизменять существующие структуры: вы должны создавать новые.