【问题标题】:What is the need of linear sequence List when there is Vector?有Vector的时候需要什么线性序列List?
【发布时间】:2017-02-01 17:42:41
【问题描述】:

Vector 是不可变的,索引的,支持随机访问,在 Scala 中高效;不可变线性序列List需要什么?

【问题讨论】:

    标签: scala collections


    【解决方案1】:

    列表是一种很常见的数据结构,如果不存在就很奇怪了。

    列表最好有前置、头部和尾部操作

    与向量相比,列表的开销更少

    如果您不需要随机访问并且只关心头/尾操作,则 List 是有意义的。如果您确实需要随机访问,那么 Vector 或其他一些数据结构更有意义。

    【讨论】:

    • 此性能图表可能有用docs.scala-lang.org/overviews/collections/… 所有向量操作都有效地保持不变。而 List 的头部、尾部和前置是总是不变的。
    • 你能解释一下你所说的“开销”是什么意思吗?对于大型集合,列表肯定比向量需要更多内存。
    • 列表的主要优点之一是,对于许多常见模式,它们支持更多的结构共享。
    【解决方案2】:

    Haoyi Li 有一个非常有趣的Blog 比较了 Scala 集合。我向任何人推荐这个。

    有一段明确比较了Lists vs Vectors

    总的来说,Lists和Vectors有很大的不同

    • 与向量相比,列表占用的空间大约是两倍。因此,如果您有数百万个元素,Vectors 就是您要走的路。
    • 对向量的随机访问实际上是 O(1),在列表上是 O(n)。
    • 通过一次添加一个元素来增长向量很慢,真的很慢。列表的速度要快一个数量级。
    • 顺序扫描列表和向量具有相同的速度。

    【讨论】:

      【解决方案3】:

      除了@marios 和@puhlen 已经提到的之外,使用传统列表(头/尾)的另一个原因是用于模式匹配。有两个类对此有帮助。

      首先是::(缺点)案例类:

      final case class ::[B](override val head: B, private[scala] var tl: List[B]) extends List[B] {
        override def tail : List[B] = tl
        override def isEmpty: Boolean = false
      }
      

      其次,有一个Nil的案例类:

      case object Nil extends List[Nothing] { 
        ...
      }
      

      (如您所见,它们都适用于 List 类型)

      这些使得列表上的模式匹配非常自然:

      list match {
        case Nil => "empty list"
        case x :: xs => s"head is $x with tail $xs"
      }
      

      【讨论】:

      • 您可以通过使用“+:”而不是“::”来对任何序列(包括 Vector)使用相同的模式。
      • 是的,我知道,但这感觉更自然consNil
      猜你喜欢
      • 1970-01-01
      • 2012-09-16
      • 2011-10-21
      • 1970-01-01
      • 2011-02-13
      • 2019-08-13
      • 2018-12-10
      • 2010-12-29
      • 2017-07-13
      相关资源
      最近更新 更多