2017-06-01 27 views
1

我對Elixir非常陌生,只是想找到將兩個地圖與同一個鍵合併的最佳方法。更具體地講:將Elixir中的同一個鍵上的兩個地圖組合在一起

name_map = %{ 
    105 => "Jim", 
    48 => "Maria", 
    62 => "Karen", 
    888 => "Foo" 
} 

job_map = %{ 
    105 => "Social worker", 
    48 => "Programmer", 
    62 => "Teacher", 
    999 => "Bar" 
} 

,我試圖讓

combined_map = %{ 
    105 => %{"name" => "Jim", "job" => "Social worker"}, 
    48 => %{"name" => "Maria", "job" => "Programmer"}, 
    62 => %{"name" => "Karen", "job" => "Teacher"}, 
    888 => %{job: nil, name: "Foo"}, 
    999 => %{job: "Bar", name: nil}} 
} 

在此先感謝您的幫助!

+1

你想要什麼如果一個密鑰只出現在一張地圖上? – Dogbert

+0

把一個零在罰款,好趕上! – phil

回答

5

一個簡單的解決方案:從另外兩個地圖的所有按鍵,遍歷鍵,並檢索從地圖值和構造元組{key, %{name: name, job: job}},然後降低到元組的地圖。

name_map = %{ 
    105 => "Jim", 
    48 => "Maria", 
    62 => "Karen", 
    888 => "Foo" 
} 

job_map = %{ 
    105 => "Social worker", 
    48 => "Programmer", 
    62 => "Teacher", 
    999 => "Bar" 
} 

combined_map = Map.keys(name_map) ++ Map.keys(job_map) 
       |> Stream.uniq 
       |> Stream.map(&{&1, %{name: name_map[&1], job: job_map[&1]}}) 
       |> Enum.into(%{}) 

%{48 => %{job: "Programmer", name: "Maria"}, 
    62 => %{job: "Teacher", name: "Karen"}, 
    105 => %{job: "Social worker", name: "Jim"}, 
    888 => %{job: nil, name: "Foo"}, 
    999 => %{job: "Bar", name: nil}} 
+0

這是一個很好的答案,但是你能解釋爲什麼你使用Stream而不是Enum(或者它只是首選項)嗎? – phil

+2

因爲'Enum.uniq'和'Enum.map'會創建中間列表,但'Stream'的對應列表不會。 – Aetherus

+0

很高興知道! :) – phil

1

將每張地圖變換爲jobname鍵下的值,然後Map.merge將條目組合。

name_map = %{ 
    105 => "Jim", 
    48 => "Maria", 
    62 => "Karen", 
} 

job_map = %{ 
    105 => "Social worker", 
    48 => "Programmer", 
    62 => "Teacher" 
} 

Map.merge(
    Enum.into(name_map, %{}, fn {k, v} -> {k, %{name: v}} end), 
    Enum.into(job_map, %{}, fn {k, v} -> {k, %{job: v}} end), 
    fn _k, v1, v2 -> Map.merge(v1, v2) end) 

%{48 => %{job: "Programmer", name: "Maria"}, 
    62 => %{job: "Teacher", name: "Karen"}, 
    105 => %{job: "Social worker", name: "Jim"}} 
3

假設你有兩個地圖相同的密鑰,這也很容易:

Map.merge(name_map, job_map, fn _k, v1, v2 -> 
    %{name: v1, job: v2} 
end) 
#⇒ %{48 => %{job: "Programmer", name: "Maria"}, 
# 62 => %{job: "Teacher", name: "Karen"}, 
# 105 => %{job: "Social worker", name: "Jim"}} 

無論你想支持的名字沒有工作,反之亦然:

Enum.into(Map.keys(name_map) ++ Map.keys(job_map), %{}, fn k -> 
    {k, %{name: Map.get(name_map, k), job: Map.get(job_map, k)}} 
end) 
#⇒ %{48 => %{job: "Programmer", name: "Maria"}, 
# 62 => %{job: "Teacher", name: "Karen"}, 
# 105 => %{job: "Social worker", name: "Jim"}, 
# 888 => %{job: nil, name: "Foo"}, 
# 999 => %{job: "Bar", name: nil}} 
相關問題