Scala Set和shuffling的排序顺序

时间:2015-05-15 19:36:00

标签: scala set shuffle

scala
Welcome to Scala version 2.10.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_79).
Type in expressions to have them evaluated.
Type :help for more information.

scala> 300 to 1000 toSet
warning: there were 1 feature warning(s); re-run with -feature for details
res0: scala.collection.immutable.Set[Int] = Set(645, 892, 809, ...)

// 问题#1:我预计当我再次运行时,订单会有所不同。它与res0的顺序相同。 所以我想,可能是因为不同的原因(系统熵等),范围太小而不同。

scala> 300 to 1000 toSet
warning: there were 1 feature warning(s); re-run with -feature for details
res1: scala.collection.immutable.Set[Int] = Set(645, 892, 809, ...)

// 问题#2:这很奇怪。即使在洗牌之后我也会看到同样的顺序。为什么?

scala> scala.util.Random.shuffle((300 to 1000).toSet)
res2: scala.collection.immutable.Set[Int] = Set(645, 892, 809, ...)

2 个答案:

答案 0 :(得分:2)

普通的Set s不保证任何顺序。这意味着它可以选择按照它选择的任何顺序存储数据,并认为这是最有效或最方便的。

它可以选择以不同的顺序存储,具体取决于项目的顺序,也可能不是。它不能保证。

重要的是,如果它恰好在一个版本的scala中这样做,取决于这个特定的结果将是危险的,因为没有明确的保证。

所以,我不知道它为什么选择这个结果,但结果实际上是任意的,你不能依赖它。对Set进行洗牌没有具体价值,因为Set可以选择按照它选择的任何顺序存储它们。

如果您需要Set中的订单,请选择TreeSetSortedSet,这可以保证元素的退货顺序。

对scala中Set实现的内部结构有更多了解的其他人可以提供有关实现细节的更详细的答案。

据我所知,默认的不可变SetHashSet实现,因此,对于任何给定的Set值,无论插入的顺序如何,桶都不太可能发生变化。

答案 1 :(得分:2)

scala中的标准不可变Set实现为 Hash Tries 。它基本上是一棵树,使用添加到它的值的哈希码。这就是它如何有效地检测Set中已存在的值。

由于添加值的哈希码无论它们添加到集合的顺序如何都是相同的,因此Set总是处于相同的顺序是合理的。当然,需要注意的是,这个顺序既不是外在的确定性,也不是保证。所以即使你喜欢Set的排序,也不能保证它不会在编译器或JVM的任何版本发布中发生变化