Scala中的Seq和IndexedSeq / LinearSeq有什么区别?

时间:2016-03-18 18:22:11

标签: scala scala-collections seq

Scala Collection documentation中,这个问题有一些线索:

  

Trait Seq有两个子线索LinearSeq和IndexedSeq。这些不添加任何新操作,但每个都提供不同的性能特征:线性序列具有有效的头部和尾部操作,而索引序列具有有效的应用,长度和(如果可变的)更新操作。

但这不能解决我何时使用IndexedSeq而不是Seq? 我需要一些IndexedSeqLinearSeq的真实示例,其中这些集合的效果优于Seq

2 个答案:

答案 0 :(得分:16)

Seq是超级特征,因此它更通用,它具有所有序列共有的特征,包括线性和索引。

如果您想知道Seq的配套对象中的Seq.apply方法创建了哪种序列,我们可以看一下实现。

请注意如果您使用Seq.apply,则表示您只需要一个Seq,并且您的代码不关心它是否为线性或索引

tl; dr答案是:当你需要具有某种表现特征时,你使用LinearSeqIndexedSeq,当你穿上时,你会使用更通用的Seq不关心差异

这是Seq

的伴随对象
object Seq extends SeqFactory[Seq] {
  implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, Seq[A]] = ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]]

  def newBuilder[A]: Builder[A, Seq[A]] = immutable.Seq.newBuilder[A]
}

newBuilder[A]方法用于构建Seq,因为您可以在Seq.apply方法中验证(在特征GenericCompanion上定义):

def apply[A](elems: A*): CC[A] = {
   if (elems.isEmpty) empty[A]
   else {
     val b = newBuilder[A]
     b ++= elems
     b.result()
   }
 }

现在的问题是:immutable.Seq.newBuilder[A]构建了什么? 我们来看看,这次是immutable.Seq伴侣对象:

object Seq extends SeqFactory[Seq] {
// stuff
  def newBuilder[A]: Builder[A, Seq[A]] = new mutable.ListBuffer
}

它构建了一个可变的ListBuffer!这是为什么?这是因为mutable.ListBuffer恰好也是Builder[A, Seq[A]],这是集合库用来构建新集合的类。

实际的输出集合来自这一行(如上所示):

b.result()

那么,ListBuffer.result()的返回类型是什么?我们来看看ListBuffer:

// Implementation of abstract method in Builder
def result: List[A] = toList

这里你去:这是一个清单。

Seq(1,2,3)返回List[Int],但这里的重点是,如果您使用的是Seq(),则无需知道您拥有的是什么类型的集合因为你暗示更抽象的界面足以满足你的需求

答案 1 :(得分:8)

Seq只是IndexedSeq和LinearSeq的超级特征。 Seq是有序列表,而不是Set,这是唯一的&通常是无序的,而不是Map,它是关键值对 现在是IndexedSeq和LinearSeq IndexedSeq子类,即Vector,Range,String,都是基于快速索引的访问,通常是快速更新。这是可能的,因为它们在内部使用适合此类数组的数据结构(如在String中)或​​树(实际上是Vector使用的32扇出树...有关详细信息,请参阅this)或Range,这是只有三个数字..开始,结束,步骤...从中可以直接计算索引 与此相反,LinearSeq都是基于慢速索引和访问的,并且更新速度很慢。通常因为他们有一种链表的结构。 Prepend对于它们所有人来说都很快,即Queue,Stack,List ..但是附加速度非常慢,因为它必须转到内部链表结构的边缘..除了队列使用技巧与它自己的问题。诀窍被描述为here 从广义上讲,IndexedSeq是那些具有快速索引访问和更新的数据结构,而LinearSeq是那些具有快速前置的数据结构。