nazevedo3
Working with Nested structures
Hi All,
I could use some help working with nested structures. I have this map:
%{
tasks: [
%{completed: false, date_added: "3.18.2021", id: 1, name: "walk the dog"},
%{completed: false, date_added: "3.18.2021", id: 2, name: "cook dinner"},
%{completed: false, date_added: "3.18.2021", id: 3, name: "laundry"}
]
}
I want to pass that map into function, along with an integer. If there’s a task with the same ID then the number that gets passed in, I want to update that map so that the “completed” field is changed to true and everything else is left unchanged.
Here’s what I have so far where I can update the map, but I’m not sure how to attach it back to the original list of maps.
def complete_item(list, item_id) do
for items_in_list <- list[:tasks], Map.get(items_in_list, :id) == item_id, do: Map.put(items_in_list, :completed, true)
end
Marked As Solved
eksperimental
The way your list is structured is non-performant, because in order to find an ID you may have to traverse the whole list, and there could be duplicates.
If you convert tasks into a map being the map key the id of the task, you can do this much easier with (as @globalkeith suggested) Kernel.update_in/2 (note it is /2 in this case)
map = %{
tasks: %{
1 => %{completed: false, date_added: "3.18.2021", name: "walk the dog"},
2 => %{completed: false, date_added: "3.18.2021", name: "cook dinner"},
3 => %{completed: false, date_added: "3.18.2021", name: "laundry"}
}
}
complete_item =
fn(map, id) ->
{_completed, update_map} = get_and_update_in(
map[:tasks][id][:completed], fn completed -> {completed, true} end
)
update_map
end
map = complete_item.(map, 1)
So your complete_item function could be rewritten like
def complete_item(map, id) do
get_and_update_in(map[:tasks][id][:completed], &{&1, true})
|> elem(1)
end
Also Liked
kokolegorille
Hello and welcome,
There are many ways to update/put a key in a map, Map.update, Map.put, Map.new/2, but in that particular case where You want to update an existing atom key in a map, You can use the form map = %{map | key: value}
You can do like this…
iex(1)> map = %{
tasks: [
%{completed: false, date_added: "3.18.2021", id: 1, name: "walk the dog"},
%{completed: false, date_added: "3.18.2021", id: 2, name: "cook dinner"},
%{completed: false, date_added: "3.18.2021", id: 3, name: "laundry"}
]
}
iex(2)> i = 1
iex(3)> map = %{map | tasks: Enum.map(map.tasks, fn
task when task.id==id -> %{task | completed: true}
task -> task
end)}
%{
tasks: [
%{completed: true, date_added: "3.18.2021", id: 1, name: "walk the dog"},
%{completed: false, date_added: "3.18.2021", id: 2, name: "cook dinner"},
%{completed: false, date_added: "3.18.2021", id: 3, name: "laundry"}
]
}
globalkeith
Another option is to use Kernel.update_in/3 which is intended to help with updating nested structures.
This will give you something to play with:
iex(1)> all = fn :get_and_update, data, next -> data |> Enum.map(next) |> Enum.unzip() end
#Function<42.97283095/3 in :erl_eval.expr/5>
iex(2)> complete_item = fn list, id -> update_in(list, [:tasks, all], fn %{id: ^id} = t -> %{t | completed: true}; t -> t end) end
#Function<43.97283095/2 in :erl_eval.expr/5>
iex(3)> list = %{
...(3)> tasks: [
...(3)> %{completed: false, date_added: "3.18.2021", id: 1, name: "walk the dog"},
...(3)> %{completed: false, date_added: "3.18.2021", id: 2, name: "cook dinner"},
...(3)> %{completed: false, date_added: "3.18.2021", id: 3, name: "laundry"}
...(3)> ]
...(3)> }
%{
tasks: [
%{completed: false, date_added: "3.18.2021", id: 1, name: "walk the dog"},
%{completed: false, date_added: "3.18.2021", id: 2, name: "cook dinner"},
%{completed: false, date_added: "3.18.2021", id: 3, name: "laundry"}
]
}
iex(4)> complete_item.(list, 2)
%{
tasks: [
%{completed: false, date_added: "3.18.2021", id: 1, name: "walk the dog"},
%{completed: true, date_added: "3.18.2021", id: 2, name: "cook dinner"},
%{completed: false, date_added: "3.18.2021", id: 3, name: "laundry"}
]
}
nazevedo3
Awesome, this is all really helpful, I appreciate it! @eksperimental - totally makes sense. I was considering changing the structure up because of that.
Thanks for the feedback!
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









