在Keyword.Merge / 3函数中删除了键

时间:2018-03-04 13:51:38

标签: elixir

当我调用以下函数时,关键字列表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]

2 个答案:

答案 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)

对于这一个,ab有两个匹配,将逐个应用。 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删除所有其他条目的方式相同,而不是简单地添加到关键字列表中。 :)