【问题标题】:Create lists of list while creating a map创建地图时创建列表列表
【发布时间】:2017-09-12 22:23:01
【问题描述】:

我写的

Enum.reduce(list, map, fn elem, map ->
  key=hd(elem)
  Map.put(map, key, List.wrap(Map.get(map, key)) ++ tl(elem))
end)

列表如下所示

['B2', ['B1', 'B2', 'B3']],
['B2', ['A1', 'A2', 'A3']],

想要的结果看起来像

B2 => [['B1', 'B2', 'B3'], ['A1', 'A2', 'A3']]

上面的代码确实产生了这个结果,但感觉特别难看。

我觉得Enum.into 可以用于更好的变体,但我似乎无法同时掌握这些值。我试过了

Enum.into(list, map, fn [k, v] -> {k, List.wrap(Map.get(map, k)) ++ v} end )

但这不会产生任何有用的东西。我相信我的大脑很难摆脱我在过去 25 年编码中使用的命令式思维方式。

【问题讨论】:

  • listmap 的示例值有助于理解问题。
  • 添加了一个例子。

标签: elixir


【解决方案1】:

虽然Enum.reduce/3 可以很好地解决此问题,但我会使用Enum.group_by/2 来阐明意图。 (如果且只有性能不是首要任务:reduce 会快得多。)

list = [
  ['A2', ['B1', 'B2', 'B3']],
  ['A2', ['A1', 'A2', 'A3']],
  ['B2', ['B1', 'B2', 'B3']],
  ['B2', ['A1', 'A2', 'A3']],
] # thanks @Dogbert for the input

list
|> Enum.group_by(&Kernel.hd/1)
|> Enum.into(%{}, fn {k, e} ->
  {k, Enum.map(e, &List.last/1)}
end)

# %{'A2' => [['B1', 'B2', 'B3'], ['A1', 'A2', 'A3']],
#   'B2' => [['B1', 'B2', 'B3'], ['A1', 'A2', 'A3']]}

【讨论】:

    【解决方案2】:

    我也会使用Enum.reduce/3,但不是Map.put/3 + List.wrap/1,而是使用Map.update/4,而不是hd/1tl/1 一些模式匹配。

    list = [
      ['A2', ['B1', 'B2', 'B3']],
      ['A2', ['A1', 'A2', 'A3']],
      ['B2', ['B1', 'B2', 'B3']],
      ['B2', ['A1', 'A2', 'A3']],
    ]
    
    list
    |> Enum.reduce(%{}, fn [k | v], acc ->
      Map.update(acc, k, v, &(&1 ++ v))
    end)
    |> IO.inspect
    

    输出:

    %{'A2' => [['B1', 'B2', 'B3'], ['A1', 'A2', 'A3']],
      'B2' => [['B1', 'B2', 'B3'], ['A1', 'A2', 'A3']]}
    

    【讨论】:

    • 我错过了Map.update 上的初始值——我认为update 只是更新。` &(&1 ++ v) ` 只是fn x -> x ++v end 的简写,如果我收集正确的话。
    【解决方案3】:

    大量建立在 Dogbert 的回答和 blog post 的基础上,我创建了自己的结构:

    defmodule MyStruct do
      defstruct []
      def fetch(map, key), do: :maps.find(key, map)
    end
    
    defimpl Collectable, for: MyStruct do
      def into(original) do
        {original, fn
          source, {:cont, [k | v ]} -> Map.update(source, k, v, &(&1 ++ v))
          source, :done -> source
        end}
      end
    end
    

    现在我可以做到了

    defmodule MyModule
      map=Enum.into(list, %MyStruct{})
    end
    

    或在理解中使用into: %MyStruct{}

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-03
      • 2015-09-27
      • 2020-11-05
      • 2020-04-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多