Shorter way to append a list of map where it could possibly exist in list of struct

Hi,

Can I ask whether if there’s a smart way to convert a list of struct to map, then update certain property of that converted list based on another list of map with same id.

For example

 poll_options =  [ 
    %Pickr.Polls.Option{
      __meta__: #Ecto.Schema.Metadata<:loaded, "options">,
      id: 23,
      inserted_at: ~N[2020-10-24 06:16:47],
      poll: #Ecto.Association.NotLoaded<association :poll is not loaded>,
      poll_id: 6,
      updated_at: ~N[2020-10-24 06:16:47],
      value: "A"
    },
    %Pickr.Polls.Option{
      __meta__: #Ecto.Schema.Metadata<:loaded, "options">,
      id: 24,
      inserted_at: ~N[2020-10-24 06:16:47],
      poll: #Ecto.Association.NotLoaded<association :poll is not loaded>,
      poll_id: 6,
      updated_at: ~N[2020-10-24 06:16:47],
      value: "B"
    },
    %Pickr.Polls.Option{
      __meta__: #Ecto.Schema.Metadata<:loaded, "options">,
      id: 25,
      inserted_at: ~N[2020-10-24 06:16:47],
      poll: #Ecto.Association.NotLoaded<association :poll is not loaded>,
      poll_id: 6,
      updated_at: ~N[2020-10-24 06:16:47],
      value: "C"
    }
  ],

Then the existing list of map

%{option_id: 23, votes: 1}]

What I want is to merge the two maps into this one. if the 1st list does not have the id in the 2nd list, the votes property will be set to 0

[
 %{option_id: 23, votes: 1},
 %{option_id: 24, votes: 0},
%{option_id: 25, votes: 0}
]

I can achieve the same result above with my code below

  defp append_votes_with_defaults(options, result) do
    options
      |> set_default_votes()
      |> remove_options_with_votes(result)
      |> append_votes_to_default_votes(result)
  end
  
  defp set_default_votes(options)  do
    Enum.map(options, fn option ->
      %{option_id: option.id, votes: 0}
    end )
  end
  
  defp remove_options_with_votes(options, result) do
    Enum.reject(options, fn opt ->
      Enum.any?(result, fn res ->
        opt.option_id == res.option_id
      end)
    end)
  end

  defp append_votes_to_default_votes(options, result) do
    options ++ result
  end

I’m just asking if there’s a shorter or efficient way to achieve the same result.

If there’s an unclear part, please let me know so I can add further information.
Thank you very much.

It seems your solution is complex.

Maybe a simpler solution could apply… not tested

Enum.map(poll_options, fn %{id: id} ->
  case Enum.find(list2, & &1.option_id == id) do
    nil -> %{option_id: id, votes: 0}
    something -> something
  end
end
1 Like