你可以对可变的Scala集合进行排序吗?

时间:2015-06-20 02:37:47

标签: scala sorting collections

是否可以对ArrayBuffer或其他可变Scala集合进行排序?我看到ArrayBuffer.sorted(和sortBy)返回一个新的集合,而Sorting.quicksort确实对一个Array进行了排序,但不能在ArrayBuffers上工作。

我问的原因是我在Spark中使用combineByKey来构建大小有限的得分对象集合(例如"前十"按键列表)。如果我合并一个新对象并且该集合已经处于容量状态,我需要删除得分最低的对象。我可以使用像PriorityQueue或SortedSet这样的已排序集合,但我不需要一直对集合进行排序,只有在集合填满时才会这样。

那么有没有办法对ArrayBuffer或ListBuffer进行排序?或者是否有其他一些支持追加和排序的集合?我确信有更好的方法可以做到这一点,但我是Scala的新手。

3 个答案:

答案 0 :(得分:4)

您可以使用Java的排序实用程序。

以下是一个例子:

val myArray = Array(1,12,5,6)
java.util.Arrays.sort(myArray)

在REPL:

> myArray
res3: Array[Int] = Array(1, 5, 6, 12)

如果您拥有的是Scala ArrayBuffer,请调用toArray将其转换为数组。

当然,toArray ArrayBuffer会导致再次处理整个缓冲区的成本。如果这样做很昂贵,请检查您是否可以使用Array代替ArrayBuffer来获得初始结果。如果结果具有固定长度且不太可能增长,那么您不需要ArrayBuffer的动态扩展功能。

答案 1 :(得分:3)

目前没有用于对集合进行分类的工具。也就是说,如果您希望极少进行排序,您可以单独调查支持,例如作为Either[PriorityQueue[A], ArrayBuffer[A]];或者如果您希望排序相当普遍,则应使用数据结构,每次添加元素时都不会支付这样的罚金 - 这意味着只需使用SortedSetPriorityQueue。否则你会很快 。 (n^2 log n很快变大,如果你在每次添加新元素时进行完整排序,就会得到这种结果。)

答案 2 :(得分:1)

您可以使用Scala的JavaConverters通过1行代码委托给Java的Arrays.sort

假设您在可变缓冲区中有Foo个实例,您希望使用比较器fooComparator对其进行排序。

import scala.collection.mutable
import scala.collection.JavaConverters._

…

val buffer = mutable.ArrayBuffer[Foo]()

…

buffer.asJava.sort(fooComparator) // sort "in place" (actually hides 1 copy)

然而,对于极端性能而言,ArrayBuffer似乎无法使用,而普通固定大小Array是可行的方法。好的是JavaConverters.asJava不会复制这些项目。但是,Java List.sort方法在内部将项目复制到Array并调用Arrays.sort。 (然后将已排序的项目分配回原始集合)

也许“完整的解决方案”是定义您自己的Scala ArrayBuffer版本,该版本公开底层数组以进行排序。由于Scala的集合库的设置方式,实现自己的集合类型可以完成与原始集合相同的事情,加上Scala中的自己的技巧通常很容易。