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

问题描述 投票:4回答:2

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

elixir
2个回答
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:Josz关闭https://github.com/elixir-lang/elixir/issues/7420说:

引用文档:

关键字可能具有重复的键,因此它不是严格意义上的键值存储。 但是,此模块中的大多数函数都与字典完全相同,因此它们的工作方式与Map模块中的函数类似。

在这种情况下,这意味着右侧的内容确实会删除左侧的所有内容。与Keyword.put删除所有其他条目的方式相同,而不是简单地添加到关键字列表中。 :)


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{a: 3}将匹配A中的第一个a,因此fn将适用于解决冲突。 A的第二个a没有比赛,将被丢弃。然后,B{b: 3}将匹配A{b: 2},也将应用fn来解决冲突。

注意

包括在关键字2中给出的重复密钥将被添加到keywords1

B{b:4}没有匹配,它将添加到A.

因此结果是[a: 4, b: 5]添加{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]将不会超越和保留。

B{b:3}将匹配A{b:2},所以使用fn解决冲突,res是{b: 5}{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]

© www.soinside.com 2019 - 2024. All rights reserved.