Scala集包含相同的元素,但sameElements()返回false

DNA*_*DNA 53 scala scala-collections

在Iterables上完成Scala 练习时,我遇到了以下奇怪的行为:

val xs = Set(5,4,3,2,1)
val ys = Set(1,2,3,4,5)
xs sameElements ys       // true

val xs = Set(3,2,1)
val ys = Set(1,2,3)
xs sameElements ys       // false - WAT?!
Run Code Online (Sandbox Code Playgroud)

当然这些集合具有相同的元素,应该忽略排序; 为什么这只能用于更大的集合?

DNA*_*DNA 94

Scala集合库为少于5个值的集合提供专门的实现(请参阅源代码).这些实现的迭代器按照添加顺序返回元素,而不是用于较大集合的基于哈希的一致排序.

此外,sameElements(scaladoc)在Iterables 上定义(它实现在IterableLike- 参见源代码); 仅当迭代器以相同的顺序返回相同的元素时,它才返回true.

因此虽然Set(1,2,3)并且Set(3,2,1) 应该是等价的,但它们的迭代器是不同的,因此sameElements返回false.

这种行为是令人惊讶的,并且可以说是一个错误,因为它违反了Set的数学期望(但仅限于某些大小的Set!).

正如IK在评论中指出的那样,==如果你只是将集合相互比较,那么工作正常,即Set(1,2,3) == Set(3,2,1).但是,sameElements更通用,因为它可以比较任何两个iterables的元素.例如,List(1, 2, 3) == Array(1, 2, 3)是假的,但是List(1, 2, 3) sameElements Array(1, 2, 3)是真的.

更一般地说,平等可能令人困惑 - 请注意:

List(1,2,3) == Vector(1,2,3)
List(1,2,3) != Set(1,2,3)
List(1,2,3) != Array(1,2,3)      
Array(1,2,3) != Array(1,2,3)
Run Code Online (Sandbox Code Playgroud)

我已经为Scala练习提交了一个解释问题的修复程序.sameElements

  • 伟大的发现......在一个大项目中,这样的事情可以让任何人发疯.你是否在官方scala问题上为此提出了一张票. (3认同)
  • 我非常喜欢 scala,但像这样的错误令人沮丧。好找。 (2认同)
  • @Zoltán,我完全同意.差异:Scala不会覆盖数组的"=="(或者至少不再覆盖).所以`==`和`sameElements`可以为数组产生不同的答案. (2认同)