假设我有两张地图( m1,m2 ),这些地图预计会有大多数相同的kv对,但每张地图可能都有其他不相同的条目。最终,我想要一张包含两张地图中所有kv对的地图,所以在高级别我想合并它们。
然而,考虑到Map.merge(Erlang BIF)和Map.split(尾递归)的实现,以及期望差异与地图大小成比例的启发式,哪个以下选项更适合达到预期的结果?
首先拆分以找到m2唯一的kv对,并仅合并那些
...
{_duplicateKeys, m2only} = Map.split(m2, Map.keys(m1))
Map.merge(m1, m2only)
...
或者只是合并,希望实现将优化构建地图
...
Map.merge(m1, m2)
...
答案 0 :(得分:3)
我会选择Map.merge
方法。过早优化通常是反模式。如果您以后发现性能问题,则可以进行优化。 Erlang BIF通常非常高效。
编辑:
这是一个快速基准
spallen@Steves-MacBook-Pro ~/myprojects/elixir/maps time ./map.exs
MapDemo running count: 5000000
./map.exs 21.30s user 2.73s system 98% cpu 24.371 total
spallen@Steves-MacBook-Pro ~/myprojects/elixir/maps time ./split.exs
SplitDemo running count: 5000000
./split.exs 25.68s user 4.28s system 98% cpu 30.479 total
这是代码
#! /usr/local/bin//elixir
defmodule MapDemo do
@upper 5000000
def run do
IO.puts "MapDemo running count: #{@upper}"
map1 =
0..@upper
|> Enum.map(& {"key_#{&1}", &1})
|> Enum.into(%{})
map2 =
100..(@upper + 100)
|> Enum.map(& {"key_#{&1}", &1})
|> Enum.into(%{})
Map.merge(map1, map2)
end
end
MapDemo.run
和
#! /usr/local/bin//elixir
defmodule SplitDemo do
@upper 5000000
def run do
IO.puts "SplitDemo running count: #{@upper}"
map1 =
0..@upper
|> Enum.map(& {"key_#{&1}", &1})
|> Enum.into(%{})
map2 =
100..(@upper + 100)
|> Enum.map(& {"key_#{&1}", &1})
|> Enum.into(%{})
{_duplicateKeys, m2only} = Map.split(map2, Map.keys(map1))
Map.merge(map1, m2only)
end
end
SplitDemo.run
答案 1 :(得分:3)
我希望split
的费用超过merge
的任何费用。
当地图很大时,看起来BIF使用的是hashmap_merge,其中包含此注释:
/*
* Strategy: Do depth-first traversal of both trees (at the same time)
* and merge each pair of nodes.
*/
实现似乎检测到地图中何时存在相同的子树:
switch (sp->mix) {
case 0: /* Nodes A and B contain the *EXACT* same sub-trees
=> fall through and reuse nodeA */
case 1: /* Only unique A stuff => reuse nodeA */
res = sp->nodeA;
break;
case 2: /* Only unique B stuff => reuse nodeB */
res = sp->nodeB;
break;
case 3: /* We have a mix => must build new node */
答案 2 :(得分:2)
在查看Map.merge BIF的文档并在#elixir-lang中与asonge讨论后,决定简单合并是合适的解决方案。
...
Map.merge(m1, m2)
...
解决方案有一些细微差别:地图的比例对于决定地图在内存中的表示方式非常重要 - flatmap for small,hashmap for large。
然而,选择简单合并是因为散列图用于优化很重要的大型地图。由于许多节点在大多数相似的地图中将比较相等,因此算法应该仅需要重建地图下面的树的一小部分。至少这是我们研究所表明的;这在实践中尚未经过测试