# Working with Nested structures

**URL:** <https://forum.elixirforum.com/t/working-with-nested-structures/38303>\
**Category:** Questions\
**Tags:** list-of-nested-map-help\
**Created:** [March 19, 2021, 7:17am UTC](https://forum.elixirforum.com/t/working-with-nested-structures/38303 "2021-03-19T07:17:06Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![nazevedo3](https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/n/c0e974/32.png) [@nazevedo3](https://forum.elixirforum.com/u/nazevedo3)\
**Post date:** [March 19, 2021, 7:17am UTC](https://forum.elixirforum.com/t/working-with-nested-structures/38303/1 "2021-03-19T07:17:06Z")

</div>

Hi All,

I could use some help working with nested structures. I have this map:

```elixir
%{
  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.

```elixir
 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

```

---

<div class="post-metadata">

**Author:** ![kokolegorille](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/kokolegorille/32/4784_2.png) [@kokolegorille](https://forum.elixirforum.com/u/kokolegorille)\
**Post date:** [March 19, 2021, 7:37am UTC](https://forum.elixirforum.com/t/working-with-nested-structures/38303/2 "2021-03-19T07:37:53Z")

</div>

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…

```elixir
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"}
  ]
}

```

---

<div class="post-metadata">

**Author:** ![globalkeith](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/globalkeith/32/22277_2.png) [@globalkeith](https://forum.elixirforum.com/u/globalkeith)\
**Post date:** [March 19, 2021, 8:49am UTC](https://forum.elixirforum.com/t/working-with-nested-structures/38303/3 "2021-03-19T08:49:49Z")

</div>

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:

```elixir
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"}
  ]
}

```

---

<div class="post-metadata">

**Author:** ![eksperimental](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/eksperimental/32/1401_2.png) [@eksperimental](https://forum.elixirforum.com/u/eksperimental)\
**Post date:** [March 19, 2021, 10:28am UTC](https://forum.elixirforum.com/t/working-with-nested-structures/38303/4 "2021-03-19T10:28:51Z")

</div>

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)

```elixir
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

```elixir
def complete_item(map, id) do
  get_and_update_in(map[:tasks][id][:completed], &{&1, true})
  |> elem(1)
end

```

---

<div class="post-metadata">

**Author:** ![nazevedo3](https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/n/c0e974/32.png) [@nazevedo3](https://forum.elixirforum.com/u/nazevedo3)\
**Post date:** [March 19, 2021, 9:45pm UTC](https://forum.elixirforum.com/t/working-with-nested-structures/38303/5 "2021-03-19T21:45:22Z")

</div>

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!
