更新和合并Maps Elixir

时间:2018-02-19 17:41:44

标签: elixir phoenix-framework

我是Elixir的新手和一般的函数式编程。我想要的是更新地图中特定键的值,然后将该地图与另一个地图合并。

这是我的初始地图:

%{      
  "_id" => "exampleaaaaaaaaaaaaaaaaaaaaaaaaa",
  "event" => "click",
  "ip" => "127.0.0.1",
  "location" => %{
    "city" => "Oklahoma City",
    "country" => "United States",
    "country_short" => "US",
    "latitude" => 35.4675598145,
    "longitude" => -97.5164337158,
    "postal_code" => "73101",
    "region" => "Oklahoma",
    "timezone" => "-05:00"
  },
  "msg" => %{
    "_id" => "exampleaaaaaaaaaaaaaaaaaaaaaaaaa",
    "_version" => "exampleaaaaaaaaaaaaaaa",
    "clicks" => [%{"ts" => 1365111111, "url" => "http://mandrill.com"}],
    "email" => "example.webhook@mandrillapp.com",
    "metadata" => %{"user_id" => 111},
    "opens" => [%{"ts" => 1365111111}],
    "sender" => "example.sender@mandrillapp.com",
    "state" => "sent",
    "subject" => "This an example webhook message",
    "tags" => ["webhook-example"],
    "ts" => 1365109999
  },
  "ts" => 1519061856,
  "url" => "http://mandrill.com",
  "user_agent" => "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.1.8) Gecko/20100317 Postbox/1.1.3",
  "user_agent_parsed" => %{
    "mobile" => false,
    "os_company" => "Apple Computer, Inc.",
    "os_company_url" => "http://www.apple.com/",
    "os_family" => "OS X",
    "os_icon" => "http://cdn.mandrill.com/img/email-client-icons/macosx.png",
    "os_name" => "OS X 10.6 Snow Leopard",
    "os_url" => "http://www.apple.com/osx/",
    "type" => "Email Client",
    "ua_company" => "Postbox, Inc.",
    "ua_company_url" => "http://www.postbox-inc.com/",
    "ua_family" => "Postbox",
    "ua_icon" => "http://cdn.mandrill.com/img/email-client-icons/postbox.png",
    "ua_name" => "Postbox 1.1.3",
    "ua_url" => "http://www.postbox-inc.com/",
    "ua_version" => "1.1.3"
  }
}

我有这个代码可以正常工作:

merge_maps = get_in_attempt(
  payload, ["msg", "clicks"]
) ++ get_in_attempt(
  payload, ["msg", "opens"]
)
main_map = %{
  "ip" => get_in(payload, ["ip"]),
  "city" => get_in(payload, ["location", "city"]),
  "user_agent" => get_in(payload, ["user_agent"]),
  "event_type" => get_in(payload, ["event"])
}

new_maps = Enum.map(merge_maps, fn elem ->
  Map.update!(elem, "ts", &DateTime.from_unix!/1)
end)
|> Enum.map(fn elem ->
  Map.merge(elem, main_map)
end)

new_maps的输出:

[       
  %{
    "city" => "Oklahoma City",
    "event_type" => "click",
    "ip" => "127.0.0.1",
    "ts" => #DateTime<2013-04-04 21:31:51Z>,
    "url" => "http://mandrill.com",
    "user_agent" => "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.1.8) Gecko/20100317 Postbox/1.1.3"
  },
  %{
    "city" => "Oklahoma City",
    "event_type" => "click",
    "ip" => "127.0.0.1",
    "ts" => #DateTime<2013-04-04 21:31:51Z>,
    "user_agent" => "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.1.8) Gecko/20100317 Postbox/1.1.3"
  }
]

我觉得在地图列表中列举两次是一种矫枉过正,但也许这是一个很好的&#34;考虑到函数式编程的不变性方面,实现它的方法。

这是&#34;最佳做法&#34;?

1 个答案:

答案 0 :(得分:1)

  

我觉得在地图列表中枚举两次是不合理的

您可以合并两个Enum.map/2调用,如下所示:

new_maps = Enum.map(merge_maps, fn elem ->
  elem
  |> Map.update!("ts", &DateTime.from_unix!/1)
  |> Map.merge(main_map)
end)

除此之外,代码对我来说很好。