当我调用以下函数时,关键字列表1中的{:a,2}永远不会被转移,但是列表2中的{:b,4}会被转移到结果列表中,即使它没有匹配对关键字列表1。有谁知道为什么?
iex> Keyword.merge([a: 1, a: 2, b: 2], [a: 3, b: 3, b: 4], fn _k, v1,v2->v1+v2 end)
[a: 4, b: 5, b: 4]
对我来说更奇怪的是,在下面的合并{:a,2}被转移到结果列表
iex>Keyword.merge([a: 1, a: 2, b: 2], [b: 3, b: 4], fn _k, v1,v2->v1+v2 end)
[a: 1, a: 2, b: 5, b: 4]
答案 0 :(得分:2)
是对的。 在第一个例子中,
A = [a: 1, a: 2, b: 2]
B = [a: 3, b: 3, b: 4]
Keyword.merge(A, B, fn _k, v1,v2->v1+v2 end)
B
' s {a: 3}
将匹配A中的第一个a,因此fn
将适用于解决冲突。 A
的第二个a
没有匹配,将被删除。
然后,B
{b: 3}
将匹配A
{b: 2}
,还将应用fn
来解决冲突。
请注意
包含在keywords2中给出的重复键的将被添加到 keywords1
,B
{b:4}
[a: 4, b: 5]
没有匹配,它会添加到A.
结果是{b: 4}
添加[a: 4, b: 5, b: 4]
,即A = [a: 1, a: 2, b: 2]
B = [b: 3, b: 4]
Keyword.merge(A, B, fn _k, v1,v2->v1+v2 end)
。
第二个例子,
B
由于A
中没有匹配的密钥,因此[a:1, a:2]
' s B
将不会覆盖并保留。
{b:3}
' A
将与{b:2}
fn
匹配,因此请使用{b: 5}
来解决冲突,res为{ {1}}。 {b: 4}
没有匹配,将被保留。
所以res是[a: 1, a: 2, b: 5, b: 4]
。
您还可以查看Keyword.merge
的文档示例。
Keyword.merge([a: 1, b: 2, a: 3], [a: 3, d: 4, a: 5], fn :a, v1, v2 ->
...> v1 + v2
...> end)
对于这一个,a
和b
有两个匹配,将逐个应用。
res为[b: 2, a: 4, d: 4, a: 8]
。
答案 1 :(得分:2)
这是一个棘手的问题。
TL; DR:这样做是为了使其与Keyword.merge/2
保持一致。
Elixir tests的摘录证明了这个问题:
fun = fn _key, _value1, value2 -> value2 end [...lots of arg1 and arg2 declarations...] assert Keyword.merge(arg1, arg2) == Keyword.merge(arg1, arg2, fun)
修复可能很简单:只需s/delete/delete_first
here:
- do_merge(tail, acc, delete(rest, key), original, fun, keywords2)
+ do_merge(tail, acc, delete_first(rest, key), original, fun, keywords2)
但是这样,正常的合并功能(没有解析器)的行为会有所不同。我将检查是否可以调整Keyword.merge/2
以符合预期的行为并填写错误/提供PR。
FWIW: https://github.com/elixir-lang/elixir/issues/7420被José关闭说:
引用文档:
关键字可能包含重复的密钥,因此它不是严格意义上的键值存储 但是,此模块中的大多数函数都与字典完全相同,因此它们的工作方式与
Map
模块中的函数类似。在这种情况下,这意味着右侧的内容会删除左侧的所有内容。与
Keyword.put
删除所有其他条目的方式相同,而不是简单地添加到关键字列表中。 :)