Reputation: 45
simple question, I have these 2 maps
[{"Africa", 1}, {"America", 2}, {"Europe", 3}]
[{"Congo", 1, 1}, {"France", 2, 3}, {"Spain", 3, 3}, {"USA", 4, 2}, {"Egypt", 5, 1}]
I want to use Enum.map and Enum.filter to get below result
[
Africa: [{"Congo", 1}, {"Egypt", 1}],
America: [{"USA", 4}],
Europe: [{"France", 2}, {"Spain", 3}]
]
I have tried with the below combination but Im not getting the expected result. Can you give some help?
Enum.map(
[{"Africa", 1}, {"America", 2}, {"Europe", 3}],
fn {continent_name, continent_id} ->
Enum.filter(
[{"Congo", 1, 1}, {"France", 2, 3}, {"Spain", 3, 3}, {"USA", 4, 2}, {"Egypt", 5, 1}],
fn {country_name, country_id, country_continent_id} ->
if continent_id == country_continent_id do
[continent_name: [{country_name, country_id}]]
end
end
)
end
)
Upvotes: 1
Views: 140
Reputation: 121010
Kernel.SpecialForms.for/1
comprehension is extremely underrated. This is probably the easiest way to go.
(for {ct, cti} <- continents,
{cy, cyi, cycti} <- countries, cti == cycti,
do: {String.to_atom(ct), {cy, cyi}})
|> Enum.reduce([], fn {k, v}, acc ->
Keyword.update(acc, k, [v], fn l -> [v | l] end)
end)
#⇒ [
# Africa: [{"Egypt", 5}, {"Congo", 1}],
# America: [{"USA", 4}],
# Europe: [{"Spain", 3}, {"France", 2}]
# ]
On the first step we go through continents, then through countries and filter the countries by continents inplace.
Upvotes: 1
Reputation: 340
This doesn't use filter, but let me know if this works for you.
continents = [{"Africa", 1}, {"America", 2}, {"Europe", 3}]
countries = [{"Congo", 1, 1}, {"France", 2, 3}, {"Spain", 3, 3}, {"USA", 4, 2}, {"Egypt", 5, 1}]
##Place countries by continent id in a map
countries_by_continent = Enum.reduce(countries,%{}, fn({name, country_id, continent_id}, countries_map) ->
case Map.get(countries_map, continent_id) do
nil -> Map.put(countries_map, continent_id, [{name, country_id}])
current_countries -> Map.put(countries_map, continent_id, current_countries ++ [{name, country_id}])
end
end)
Enum.map(continents, fn({continent_name, continent_id}) ->
["#{continent_name}": Map.get(countries_by_continent, continent_id)]
end)
Upvotes: 0
Reputation: 23147
Here's my attempt:
continents =
[{"Africa", 1}, {"America", 2}, {"Europe", 3}]
|> Map.new(fn {a, b} -> {b, String.to_atom(a)} end)
[
{"Congo", 1, 1},
{"France", 2, 3},
{"Spain", 3, 3},
{"USA", 4, 2},
{"Egypt", 5, 1}
]
|> Enum.group_by(&elem(&1, 2), &Tuple.delete_at(&1, 2))
|> Enum.map(fn {id, list} -> {continents[id], list} end)
Output:
[
Africa: [{"Congo", 1}, {"Egypt", 5}],
America: [{"USA", 4}],
Europe: [{"France", 2}, {"Spain", 3}]
]
Upvotes: 1
Reputation: 2813
I would like to use Enum.group_by/3
iex()> cons = [{"Africa", 1}, {"America", 2}, {"Europe", 3}]
iex()> countries = [{"Congo", 1, 1}, {"France", 2, 3}, {"Spain", 3, 3}, {"USA", 4, 2}, {"Egypt", 5, 1}]
iex()> countries = Enum.group_by(countries, fn {_, _, group_key} -> group_key end, fn {country, val, _} -> {country, val} end) |> Enum.into([])
[
{1, [{"Congo", 1}, {"Egypt", 5}]},
{2, [{"USA", 4}]},
{3, [{"France", 2}, {"Spain", 3}]}
]
iex()> for {con, key_to_match} <- cons, {k, grouped_country} <- countries, key_to_match == k do
...()> [{String.to_atom(con), grouped_country}]
...()> end
[
[Africa: [{"Congo", 1}, {"Egypt", 5}]],
[America: [{"USA", 4}]],
[Europe: [{"France", 2}, {"Spain", 3}]]
]
Upvotes: 1