web-dev-qa-db-ja.com

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

確かにこれらのセットは同じ要素を持ち、順序を無視する必要があります。そして、なぜこれが大きなセットでのみ期待どおりに機能するのですか?

53
DNA

Scalaコレクションライブラリは、5個未満の値のセットに特化した実装を提供します( source を参照)。これらの実装の反復子は要素を返します大きいセットに使用される一貫したハッシュベースの順序ではなく、追加された順序

さらに、sameElementsscaladoc )はIterablesで定義されています(IterableLikeで実装されています- source を参照) ;反復子が同じ要素を同じ順序で返す場合にのみtrueを返します。

そのため、Set(1,2,3)Set(3,2,1)は同等である必要がありますが、イテレータは異なるため、sameElementsはfalseを返します。

この動作は驚くべきことであり、セットの数学的期待に違反するため、間違いなくバグです(ただし、特定のサイズのセットのみ)。

I.K.としてコメントで指摘しているように、セットを互いに比較しているだけの場合、_==_は正常に機能します。つまり、Set(1,2,3) == Set(3,2,1)です。ただし、sameElementsは、2つの反復可能要素の要素を比較できるという点でより一般的です。たとえば、List(1, 2, 3) == Array(1, 2, 3)はfalseですが、List(1, 2, 3) sameElements Array(1, 2, 3)はtrueです。

より一般的には、平等は混乱を招く可能性があります-以下に注意してください:

_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の問題を説明しています。

94
DNA