Elixir의 지도를 완전 병합

Elixir의 지도를 깊이 병합하는 방법

はじめに



たまたまあるElixirのソースコードを読んでいたらdeep mergeしてたので面白いな〜と思い調べるに至りました.

Elixir標準의 Map.merge/2



https://hexdocs.pm/elixir/Map.html#merge/3

Elixir는 言語には標準の Map.merge/2가 가능합니다.

%{a: 1} |> Map.merge(%{b: 2}) |> Map.merge(%{c: 3})
# %{a: 1, b: 2, c: 3}


しかしながら、Mapの構造が入れ子になっている場合、再帰的に統合することはしてくれません.

entry1 = %{"a" => %{"b" => %{"c1" => "hello", "c2" => "world" }}}
entry2 = %{"a" => %{"b" => %{"c1" => "コンニチハ", "c2" => "セカイ" }}}
entry3 = %{"a" => %{"b" => %{"c3" => "elixir" }}}

entry1 |> Map.merge(entry2) |> Map.merge(entry3)
# %{"a" => %{"b" => %{"c3" => "elixir"}}}


欲しい結果が以下のようなものである場合、悩まされるかもしれません.

%{
  "a" => %{
    "b" => %{"c1" => "コンニチハ", "c2" => "セカイ", "c3" => "elixir"}
  }
}


そこで登場するのがdeep_merge 입니다.

やり方はいくつか考えられます.

deep_merge (A)



今回の調査のきっかけとなった実装입니다.

https://github.com/fhunleth/beam_benchmarks/blob/6f970bff5b9291ffe2ddc849afbeabeea6595baf/lib/beam_benchmarks/info.ex#L89

defmodule MapUtils1 do
  def deep_merge(map1, map2) when is_map(map1) and is_map(map2) do
    Map.merge(map1, map2, fn _key, value1, value2 -> deep_merge(value1, value2) end)
  end

  def deep_merge(not_map1, not_map2), do: not_map2
end

entry1 |> MapUtils1.deep_merge(entry2) |> MapUtils1.deep_merge(entry3)


deep_merge (비)



nettで調べて出てきたのがこれです.

https://stackoverflow.com/questions/38864001/elixir-how-to-deep-merge-maps/38865647#38865647

defmodule MapUtils2 do
  def deep_merge(left, right) do
    Map.merge(left, right, &deep_resolve/3)
  end

  defp deep_resolve(_key, left = %{}, right = %{}) do
    deep_merge(left, right)
  end

  defp deep_resolve(_key, _left, right) do
    right
  end
end

entry1 |> MapUtils2.deep_merge(entry2) |> MapUtils2.deep_merge(entry3)


deep_merge (C)


  • もっと簡潔に書けないかと思い、ボクノカンGAEtasaikyowono deep_merge を書きました.
  • Frank의 実装가 一番簡潔말하는 えばそうなのですが, 関数を一個にまとめてみたかったです, あと個人的に無名関数のにばそうなのですが、関数を一個にまとめてみたかったです, あと個人的に無名関数のにばそうなのですがの見た目がいか.

  • defmodule MapUtils3 do
      def deep_merge(left, right) do
        Map.merge(left, right, fn
          _key, l = %{}, r = %{} -> deep_merge(l, r)
          _key, _l, r ->  r
        end)
      end
    end
    
    entry1 |> MapUtils3.deep_merge(entry2) |> MapUtils3.deep_merge(entry3)
    


    deep_merge ( 키워드 型)



  • Config モジュールの内部に Keyword 型の設定データーを deep_merge する __merge__/2 그렇담 関数がありました.
  • deep_mergeKeyword 型に対して実施したい場合に参考になるかもしれません.

  • https://github.com/elixir-lang/elixir/blob/6764de46cbd21003c54a0072cc3b9a6d9dffea16/lib/elixir/lib/config.ex#L328-L340

    deep_merge ( 키워드 型와 지도 型両方)


  • 必要であれば Map 型と Keyword 型の両方に対応する こともできそうです.

  • defmodule MapUtils5 do
      def deep_merge(map1, map2) when is_map(map1) and is_map(map2) do
        Map.merge(map1, map2, fn _key, value1, value2 -> deep_merge(value1, value2) end)
      end
    
      def deep_merge(kw1, kw2) when is_list(kw1) and is_list(kw2) do
        Keyword.merge(kw1, kw2, fn _key, value1, value2 -> deep_merge(value1, value2) end)
      end
    
      def deep_merge(_not_map1, not_map2), do: not_map2
    end
    
    # Map
    entry1 = %{"a" => %{"b" => %{"c1" => "hello", "c2" => "world" }}}
    entry2 = %{"a" => %{"b" => %{"c1" => "コンニチハ", "c2" => "セカイ" }}}
    entry3 = %{"a" => %{"b" => %{"c3" => "elixir" }}}
    
    entry1 |> MapUtils5.deep_merge(entry2) |> MapUtils5.deep_merge(entry3)
    
    # Keyword
    entry1 = [a: [b: [c1: "hello", c2: "world" ]]]
    entry2 = [a: [b: [c1: "コンニチハ", c2: "セカイ" ]]]
    entry3 = [a: [b: [c3: "elixir" ]]]
    
    entry1 |> MapUtils5.deep_merge(entry2) |> MapUtils5.deep_merge(entry3)
    


    deep_merge (헥스팍케이지)


  • deep_merge 関連の色んな機能がHexpacke-jiにされています.
  • ほとんどの場合、上述の知識を持って自分で関数を書いた方が早いと思いますが、싱프르나実装では対処できない特殊な場合に活躍する9.

    https://github.com/PragTob/deep_merge

    iex
    
    Mix.install([:deep_merge])
    
    entry1 |> DeepMerge.deep_merge(entry2) |> DeepMerge.deep_merge(entry3)
    


    さいごに



    Elixir를 楽しみましょう!

    https://qiita.com/piacerex/items/e5590fa287d3c89eeebf

    https://qiita.com/torifukukaiou/items/1edb3e961acf002478fd

    各コMUNITIの詳細は、「ElixirコMUNITIの歩き方 -国内온라인編-」をご覧ください





    各種Elixiribent の開催予定は、「Elixirivevent カレンダー」から確認/参加できます 📆

  • 좋은 웹페이지 즐겨찾기