【问题标题】:Scala Sets contain the same elements, but sameElements() returns falseScala Set 包含相同的元素,但 sameElements() 返回 false
【发布时间】:2019-01-17 02:34:34
【问题描述】:

在使用 Scala exercises on Iterables 时,我遇到了以下奇怪的行为:

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?!

这些集合肯定有相同的元素,应该忽略排序;为什么这仅适用于较大的集合?

【问题讨论】:

  • 使用== 来测试是否相等,而不考虑顺序和重复。
  • 这是比较Sets 的一个好点,虽然我刚刚注意到List(1,2,3) == Vector(1,2,3) 但List(1,2,3) != Set(1,2,3) 和List(1,2,3) != Array(1,2,3) 这是另一个潜在的雷区!
  • 正如 Paul Draper 在下面的 cmets 中指出的那样,Array(1,2,3) != Array(1,2,3) !!

标签: scala scala-collections


【解决方案1】:

Scala 集合库为少于 5 个值的集合提供了专门的实现(请参阅source)。这些实现的迭代器按照它们被添加的顺序返回元素,而不是用于较大集合的一致的、基于散列的排序。

此外,sameElements (scaladoc) 在Iterables 上定义(它在IterableLike 中实现 - 参见source);只有当迭代器以相同的顺序返回相同的元素时,它才会返回 true。

所以虽然Set(1,2,3)和Set(3,2,1)应该是等价的,但是它们的迭代器不同,所以sameElements返回false。

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

作为 I.K.在 cmets 中指出,== 工作正常,如果您只是将 Set 相互比较,即Set(1,2,3) == Set(3,2,1)。但是,sameElements 更通用,因为它可以比较任意两个可迭代对象的元素。例如,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)

我有submitted a fix 用于解释sameElements 问题的Scala exercises。

【讨论】:

  • 通过方法的名称,我希望它不管集合类型如何都会忽略顺序。例如。我希望List(1,2,3) sameElements List(3,2,1) 评估为true,因为两者包含相同的元素。如果顺序很重要,那么sameElements 和== 之间的预期区别是什么?
  • 很棒的发现...在一个大项目中,这样的事情可能会让任何人发疯。你有没有在官方的 scala 问题中为此提出过票。
  • 我非常喜欢 scala,但像这样的错误是如此令人沮丧。很好的发现。
  • @Sarvesh_Kumar_Singh 在 scala-debate 列表中讨论了 here,但没有提到任何票...
  • @Zoltán,我完全同意。不同之处在于:Scala 不会为数组覆盖 ==(或至少不再覆盖)。所以== 和sameElements 可以为数组产生不同的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-17
相关资源
最近更新 更多