Подтвердить что ты не робот

Scala Наборы содержат одни и те же элементы, но sameElements() возвращает false

Во время выполнения упражнений Scala на 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?!

Несомненно, эти наборы имеют одинаковые элементы и должны игнорировать порядок; и почему это работает, как ожидалось, только для большего набора?

4b9b3361

Ответ 1

Библиотека коллекций Scala предоставляет специализированные реализации для наборов из менее чем 5 значений (см. источник). Итераторы для этих реализаций возвращают элементы в том порядке, в котором они были добавлены, а не в согласованном порядке на основе хешей, используемом для больших наборов.

Кроме того, sameElements (scaladoc) определяется на Iterable (он реализован в IterableLike - см. источник); он возвращает true, только если итераторы возвращают одни и те же элементы в том же порядке.

Итак, хотя Set(1,2,3) и Set(3,2,1) должны быть эквивалентными, их итераторы разные, поэтому sameElements возвращает false.

Такое поведение является неожиданным и, возможно, ошибкой, поскольку оно нарушает математические ожидания для Set (но только для определенных размеров Set!).

Как И.К. указывает в комментариях, == отлично работает, если вы просто сравниваете Sets друг с другом, т.е. 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)

У меня отправлено исправление для упражнений Scala, что объясняет проблему sameElements.