list - 连接列表的有效方法是什么?

标签 list scala concatenation

当我们有两个列表时 ab ,如何以有效的方式将这两个(顺序无关)连接到一个新列表?

如果 a ::: b,我无法从 Scala API 中弄清楚和 a ++ b是有效的。也许我错过了什么。

最佳答案

在 Scala 2.9 中,::: 的代码(添加到列表中)如下:

def :::[B >: A](prefix: List[B]): List[B] =
  if (isEmpty) prefix
  else (new ListBuffer[B] ++= prefix).prependToList(this)

++更通用,因为它需要一个 CanBuildFrom参数,即它可以返回一个不同于 List 的集合类型:
override def ++[B >: A, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That = {
  val b = bf(this)
  if (b.isInstanceOf[ListBuffer[_]]) (this ::: that.seq.toList).asInstanceOf[That]
  else super.++(that)
}

所以如果你的返回类型是 List ,两者表现相同。
ListBuffer是一种聪明的机制,因为它可以用作变异构建器,但最终被 toList“消耗”。方法。那又怎样(new ListBuffer[B] ++= prefix).prependToList(this)做的,是先将prefix中的所有元素依次相加(在示例中 a ),花费 O(|a|) 时间。然后它调用 prependToList ,这是一个恒定时间操作(接收器,或 b,不需要拆开)。因此,总时间为O(|a|)。

另一方面,正如 pst 指出的,我们有 reverse_::: :
def reverse_:::[B >: A](prefix: List[B]): List[B] = {
  var these: List[B] = this
  var pres = prefix
  while (!pres.isEmpty) {
    these = pres.head :: these
    pres = pres.tail
  }
  these
}

所以与 a reverse_::: b ,这又需要 O(|a|),因此效率并不比其他两种方法多多少少(尽管对于小列表大小,您可以节省中间创建 ListBuffer 的开销)。

换句话说,如果您了解 a 的相对大小和 b ,您应该确保前缀是两个列表中较小的一个。如果您没有这些知识,您将无能为力,因为 sizeList 的操作需要 O(N) :)

另一方面,在 future 的 Scala 版本中,您可能会看到改进的 Vector连接算法,如 this ScalaDays talk 中所示.它 promise 在 O(log N) 时间内解决任务。

关于list - 连接列表的有效方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11568327/

相关文章:

java - 无法将 IntelliJ IDEA 程序编译为可运行的 JAR

python - 在 Python 中合并具有不同日期范围的多个列

Python append() 与列表上的 + 运算符,为什么这些会给出不同的结果?

matlab - 用于在 JVM 上进行富有表现力的、功能丰富的数值计算的工具

java - Scala - 如何在 Spark SQL 查询中将日期字符串转换为时间戳?

javascript - Grunt 文件默认将 nonull 设置为 true

ffmpeg 声音与 -concat 或 -ss 不同步

python - 检查字符串是否在数组中

python - 如何使用 Python 将列表组成的值与字典中的常见项组合起来?

java - 列表/映射中的列表和字符串