【问题标题】:Using Enum.map to create a key map使用 Enum.map 创建键映射
【发布时间】:2019-10-22 12:18:16
【问题描述】:

简单的问题,我有这两张地图

[{"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
)

【问题讨论】:

    标签: elixir


    【解决方案1】:

    我想使用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}]]
    ]
    

    【讨论】:

    • 谢谢,但仍然不是预期的结果
    • 预期结果:[ ["Africa": [{"Congo", 1}, {"Egypt", 5}]], ["America": [{"USA", 4}]], ["Europe": [{"France", 2}, {"Spain", 3}]] ]
    • 换句话说,结果是[ "continent": [{"country1", contry_id},{"country2", contry_id}, .....]] 的列表,其中大陆在引号内(打印为字符串),后跟一列
    • 只是我忘记了这个变量的类型"key": value,我认为这是一张地图,但我不确定
    • 所以这是关键字列表elixir-lang.org/getting-started/…,你的关键是原子。你可以使用String.to_atom/1
    【解决方案2】:

    这是我的尝试:

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

    【讨论】:

    • 这是一个非常实用的方法,亚当,太好了
    【解决方案3】:

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

    第一步,我们遍历大陆,然后通过国家按大陆过滤国家就地

    【讨论】:

      【解决方案4】:

      这不使用过滤器,但让我知道这是否适合你。

      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)
      

      【讨论】:

      • 没有。预期结果是[ ["Africa": [{"Congo", 1}, {"Egypt", 5}]], ["America": [{"USA", 4}]], ["Europe": [{"France", 2}, {"Spain", 3}]] ]
      • 但是你提供的脚本的结果是[ [Africa: [{"Congo", 1}, {"Egypt", 5}]], [America: [{"USA", 4}]], [Europe: [{"France", 2}, {"Spain", 3}]] ]
      • 换句话说,大陆名称应该是字符串
      • 它是因为你期望一个关键字列表作为结果,如果你期望一个你必须使用的字符串,touples。就像 TheAnh 的解决方案
      • 你在遍历结果时改变 do Atom.to_string
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-13
      • 1970-01-01
      • 2018-01-10
      • 1970-01-01
      • 2023-03-06
      相关资源
      最近更新 更多