【问题标题】:Scala equivalent of java.util.ArrayListScala 等效于 java.util.ArrayList
【发布时间】:2012-01-07 09:52:24
【问题描述】:

我正在使用 Scala 做一个项目,但对这门语言相当陌生,并且有 Java 背景。我看到 Scala 没有 ArrayList,所以我想知道 Scala 相当于 Java 的 ArrayList 的名称,以及 Java 和 Scala 版本之间是否有任何重要区别。

编辑:我不是在寻找特定行为,而是在寻找内部表示(数据存储在数组中,但整个数组不可见,只有您使用的部分)。

【问题讨论】:

  • 整个数组可见与您使用的部分有什么区别?
  • @Daniel,对我来说主要区别是 ArrayList 为我处理大小(即,如果我不知道它会提前是什么或知道它会改变,我没有担心分配额外空间并跟踪我实际使用了多少空间)。

标签: java scala arraylist


【解决方案1】:

我可以想出 3 个更具体的问题来解决您的问题:

  • Scala 的默认集合是什么?
  • 什么 Scala 集合具有类似于ArrayList 的特征?
  • 在 Scala 中,Array 有什么好的替代品?

以下是这些问题的答案:

Scala 的默认集合是什么?

Scala 等效于 Java 的 List 接口是 Seq。还存在一个更通用的接口,即GenSeq——主要区别在于GenSeq 可能具有串行或并行处理的操作,具体取决于实现。

因为 Scala 允许程序员将Seq 用作工厂,所以他们通常不会费心去定义特定的实现,除非他们关心它。当他们这样做时,他们通常会选择 Scala 的ListVector。它们都是不可变的,Vector 具有良好的索引访问性能。另一方面,List 的操作做得很好。

什么 Scala 集合具有类似于ArrayList 的特征?

那就是scala.collection.mutable.ArrayBuffer

在 Scala 中,Array 有什么好的替代品?

好吧,好消息是,您可以在 Scala 中使用 Array!在 Java 中,Array 通常被避免使用,因为它与泛型不兼容。它是一个协变集合,而泛型是不变的,它是可变的——这使得它的协变成为一种危险,它接受泛型不接受的原语,并且它的方法集非常有限。

在 Scala 中,Array - 与 Java 中的 Array 仍然相同 - 是不变的,这使得大多数问题都消失了。 Scala 接受AnyVal(相当于原语)作为其“泛型”的类型,即使它会进行自动装箱。并且通过“丰富我的库”模式,SeqALL 方法可供Array 使用。

所以,如果您想要更强大的Array,只需使用Array

如何缩小和增长的集合?

所有集合可用的默认方法都产生集合。例如,如果我这样做:

val ys = xs filter (x => x % 2 == 0)

那么ys 将是一个 集合,而xs 仍将与此命令之前相同。不管xs 是什么:ArrayList 等都是如此。

当然,这是有代价的——毕竟,您正在制作一个新系列。 Scala 的不可变集合在处理这种成本方面要好得多,因为它们是持久的,但这取决于执行的操作。

没有集合可以对filter 做很多事情,但是List 在通过添加元素或移除头部来生成新集合方面具有出色的性能——事实上,这是堆栈的基本操作。 Vector 在一堆操作上都有不错的表现,但只有在集合不小的情况下才值得。例如,对于多达一百个元素的集合,总成本可能会超过收益。

因此,您实际上可以向Array 添加或删除元素,Scala 将为您生成一个新的 Array,但您需要支付完整副本的费用那个。

Scala 可变集合添加了一些其他方法。特别是,可以增加或减少大小的集合——而不产生新集合——实现GrowableShrinkable 特征。不过,它们并不能保证这些操作的良好性能,但它们会为您指出要检查的集合。

【讨论】:

  • Here 是一个在线测试,表明ArrayListLinkedList 快约3 倍,尽管进行了必要的重新分配。我必须减少 N 才能使其在线工作。在我自己的机器上使用N = 50000000ArrayListLinkedList 快大约 10 倍。你在你的机器上得到什么结果?如果LinkedList 更快,我会感到非常惊讶,因为它每次插入(时间)需要更多的分配,并且每个元素都需要一个额外的 Node 对象(空间)。
  • @DanielC.Sobral: Here 是一项后续在线测试,显示 ArrayList 在中间插入时比 LinkedList 快 12 倍。 LinkedList 只会出现更快when inserting near the beginning
  • @DanielC.Sobral: 不断增长的ArrayList 每次重新分配时大小都会翻倍,这意味着您最多可以复制两倍的元素——或者换句话说,平均而言,每个元素被复制 两次。不管你增加多少阵列,就是这样。作为回报,您可以获得更高效的数据结构,具有更好的局部性和缓存特性。链表实际上从来没有更快。如果您从不需要查找元素,并且您需要遍历数据结构,那么链表可能会更快。否则?没有。
  • @DanielC.Sobral:在这些情况下,ArrayList通常仍然会更快,因为它更少的分配、更少的间接性、更好的内存局部性。请记住,插入列表的中间需要您迭代以找到中间。这对于链表来说要慢得多。经验法则是“对于某些事情,很明显ArrayList 更快。对于其他事情,令人惊讶的是ArrayList 更快”。 :)
  • 并非总是如此,但 CPU 和内存性能之间的差距已经变得非常大。随机内存访问非常缓慢,而链表是所有随机访问。 ArrayList(或任何其他动态数组数据结构)实际上没有随机访问。从硬件的角度来看,这是一个巨大的优势,几乎无论您对数据结构执行哪些操作
【解决方案2】:

很难确切地说出你应该做什么,因为你还没有说你有兴趣使用ArrayList 的什么行为。考虑要利用哪些 scala 特征会更有用。这是一个很好的解释:http://grahamhackingscala.blogspot.com/2010/02/how-to-convert-java-list-to-scala-list.html

也就是说,您可能想要某种IndexedSeq

【讨论】:

    【解决方案3】:

    这是来自scala.collection.mutableArrayBuffer。你可以找到 scaladocs here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-29
      • 2013-12-15
      • 1970-01-01
      • 2016-01-08
      相关资源
      最近更新 更多