Использование Enum.map для создания карты ключей - PullRequest
1 голос
/ 19 октября 2019

простой вопрос, у меня есть эти 2 карты

[{"Africa", 1}, {"America", 2}, {"Europe", 3}]
[{"Congo", 1, 1}, {"France", 2, 3}, {"Spain", 3, 3}, {"USA", 4, 2}, {"Egypt", 5, 1}]

Я хочу использовать Enum.map и Enum.filter, чтобы получить результат ниже

[
  Africa: [{"Congo", 1}, {"Egypt", 1}],
  America: [{"USA", 4}],
  Europe: [{"France", 2}, {"Spain", 3}]
]

Я пыталсяс комбинацией ниже, но я не получаю ожидаемый результат. Можете ли вы помочь?

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
)

Ответы [ 4 ]

1 голос
/ 22 октября 2019

Kernel.SpecialForms.for/1 понимание крайне недооценено. Вероятно, это самый простой путь.

(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}]
#  ]

На первом шаге мы проходим через континенты, затем через страны и фильтруем страны по континентам на месте .

1 голос
/ 19 октября 2019

Я хотел бы использовать 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}]]
]
1 голос
/ 19 октября 2019

Вот моя попытка:

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)

Вывод:

[
  Africa: [{"Congo", 1}, {"Egypt", 5}],
  America: [{"USA", 4}],
  Europe: [{"France", 2}, {"Spain", 3}]
]
0 голосов
/ 19 октября 2019

Это не использует фильтр, но дайте мне знать, если это работает для вас.

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)
...