Creating a new list from a different list of different size

I want to create a function that takes an input like this:

[
      %{count: 2, members: [1, 4], group_rating: 13, ratings: [8, 5]},
      %{count: 1, members: [2], group_rating: 6, ratings: [6]},
      %{count: 1, members: [3], group_rating: 7, ratings: [7]}
    ]

And spits out result (order doesn’t matter)

[ %{rating: 5, member_id: 4}, 
%{rating: 8, member_id: 1}  , 
%{rating: 6, member_id: 2} ,
 %{rating: 7, member_id: 3}  ]

I tried creating an empty list then adding to that list in a for loop but that doesn’t work.

Of course that will not work, because in Elixir variables are immutable - once you set a value then these value never cannot change.

However you were this close to finishing it. First of all - Elixir do not have loops, it has comprehensions. Which mean that for do not just iterate over data, it will also produce new list. You also can iterate more structures to create product. So in this case you can do:

    # Traverse and extract data
for %{members: members, ratings: ratings} <- list,
    # Zipping will create binary tuples from 2 lists
    {id, rating} <- Enum.zip(members, ratings),
    # Create result value
    do: %{member_id: id, rating: rating}
2 Likes

Code sample

Enum.flat_map(input, fn map ->
  map.members
  |> Enum.map_reduce(map.ratings, fn member_id, [rating | ratings] ->
    {%{member_id: member_id, rating: rating}, ratings}
  end)
  |> elem(0)
end)

How it works

  1. Maps the enumerable so that the result of a function is flatten instead of added to the result list (like map function does)
  2. For each map in said list we map members with reducing their ratings using a [head | tail] notation
  3. For each member_id we create a new map with it and its rating, which is part of a list (point 2) which is flattened into final result (point 1)

Helpful resources

  1. Enum.flat_map/2
  2. Enum.map_reduce/3
  3. fn/1 (special form for creating an anonymous functions)
  4. Lists section in the Patterns and guards guide