为什么在将较低的字母表放入Set
?
的Haskell
λ: import Data.Set as S
λ: Prelude.foldr (\e acc -> S.insert e acc) S.empty ['a' .. 'z']
fromList "abcdefghijklmnopqrstuvwxyz"
Scala的
scala> ('a' to 'z').toList.toSet
res5: scala.collection.immutable.Set[Char] = Set(e, s, x, n, j, y, t,
u, f, a, m, i, v, q, b, g, l, p, c, h, r, w, k, o, z, d)
答案 0 :(得分:8)
scala的默认设置实现是一个哈希集,因此它没有排序。 Haskell中的默认设置实现是一个有序的排序集。 (您需要Ord
个实例来插入新元素:insert :: Ord a => a -> Set a -> Set a
)
要保留scala中的顺序,您必须使用SortedSet,如下所示:
scala> import scala.collection.immutable._
scala> ('a' to 'z').to[SortedSet]
res4: scala.collection.immutable.SortedSet[Char] = TreeSet(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z)
以下是关于不同选择的一些背景知识:
Scala选择基于散列的实现,因为这在JVM世界中很常见,并且因为散列表通常比排序集合快得多。这样做的缺点是哈希码引入了一些非确定性,特别是当与使用默认哈希码实现的类结合时。
Haskell将纯度置于性能之上,因此它选择了更具确定性的已排序集合。
答案 1 :(得分:2)
Set
只是一个名称,用于描述未排序且不允许重复元素的数据结构。其他一切基本上都与实现有关。
您现在已经体验到Haskell中的Set是有序的,即它的元素需要一个Ord
实例来定义它们的小于关系。 Scala的Set
特性的默认实现似乎是一个HashSet,因此顺序似乎是随机的;实际上它反映了桶元素的顺序。
在很多情况下,当一个集合是正确的数据结构时,排序无关紧要(检查成员资格,跟踪不同对象的数量,......)。如果是这样,Scala中的专用选项与Set
特征具有更严格的契约,就像Java:SortedSet
对于具有逻辑顺序的元素,或LinkedHashSet
,它们保留迭代的插入顺序,但使用散列集数据结构进行常规的集合操作。