Can you sort a mutable Scala collection in place?

scala sort list of tuples
scala ordering
sortby in spark

Is it possible to sort an ArrayBuffer, or other mutable Scala collection, in place? I see that ArrayBuffer.sorted (and sortBy) returns a new collection, and Sorting.quicksort does sort an Array in place but doesn't work on ArrayBuffers.

The reason I ask is that I'm using combineByKey in Spark to build collections of scored objects that are limited in size (like a "top ten" list by key). If I merge in a new object and the collection is already at capacity, I need to drop the lowest-scored object. I could use a sorted collection like a PriorityQueue or SortedSet, but I don't need to keep the collections sorted all the time, only in the case when a collection fills up.

So is there some way to sort an ArrayBuffer or ListBuffer in place? Or is there some other collection that supports appending and sorting in place? I'm sure there's a better way to do this, but I'm new to Scala.

There are presently no facilities for sorting collections in place. That said, if you expect to have to do sorting extremely rarely, you could investigate supporting both separately e.g. as Either[PriorityQueue[A], ArrayBuffer[A]]; or if you expect sorting to be fairly common you should use a data structure where you don't pay such a penalty each time you add an element--meaning just use the SortedSet or PriorityQueue. Otherwise you'll get slow really fast. (n^2 log n gets big quickly, which is what you get if you do a full sort each time you add a new element.)

In-place mapping and sorting to mutable collections · Issue #25 , You want to sort a sequential collection. Or, you want to implement the Ordered trait in a custom class so you can use the sorted method, or  I'd say that mutable collections are always fast and require caution for correctness, where as immutable collections are always correct and require caution to be fast (eg. linked list prepend vs append).

You can use Java's sorting utilities.

Here is an example:

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

At the REPL:

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

If what you have is a Scala ArrayBuffer then call toArray to convert it to an Array.

Of course, the toArray on ArrayBuffer induces the cost of coping the entire Buffer again. If this is costly, check if you can get your initial results in an Array instead of an ArrayBuffer. If the results are of fixed length and unlikely to grow, then you don't rally need the dynamic expansion features of ArrayBuffer.

How to sort Scala collections classes (sortWith, sorted, Ordered , You can sort the map by key, from low to high, using sortBy : scala> import scala.​collection.immutable.ListMap import scala.collection.immutable. the sequence to printAll as a separate argument, instead of passing fruits as a  there presently no facilities sorting collections in place. said, if expect have sorting extremely rarely, investigate supporting both separately e.g. either[priorityqueue[a], arraybuffer[a]]; or if expect sorting common should use data structure don't pay such penalty each time add element--meaning use sortedset or priorityqueue. otherwise you'll slow really fast.

You can use Scala's JavaConverters to delegate to Java's Arrays.sort with 1 line of code.

Assume you have instances of Foo in a mutable buffer that you want to sort in place with the comparator 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)

However for extreme performance it seems that ArrayBuffer just can't be used and the plain fixed size Array is the way to go. The good thing is that JavaConverters.asJava does not copy the items. However Java's List.sort method internally copies the items to an Array and calls Arrays.sort. (It then assigns the sorted items back to original collection)

Perhaps the "full solution" would be to define your own version of Scala's ArrayBuffer that exposes the underlying array for sorting. Implementing your own collection types that can do all the same things as the original, plus your own tricks in Scala is usually easy due to the way how Scala's collection library is set up.

How to sort a Scala Map by key or value (sortBy, sortWith , Sorting provides methods where you can provide a comparison function, or can request a sort Sort array a with quicksort, using the Ordering on its elements. Mutable and Immutable Collections. Scala collections systematically distinguish between mutable and immutable collections. A mutable collection can be updated or extended in place. This means you can change, add, or remove elements of a collection as a side effect. Immutable collections, by contrast, never change.

Scala Standard Library 2.13.1, def ++(xs: GenTraversableOnce[A]): ListBuffer[A]. Creates a new collection containing both the elements of this collection and the provided traversable object. Queues. Scala provides mutable queues in addition to immutable ones. You use a mQueue similarly to how you use an immutable one, but instead of enqueue, you use the += and ++= operators to append. Also, on a mutable queue, the dequeue method will just remove the head element from the queue and return it.

scala.collection.mutable.ListBuffer, You can sort the map by key, from low to high, using sortBy : scala> import scala.​collection.immutable.ListMap import scala.collection.immutable.ListMap scala>  Scala collections systematically distinguish between mutable and immutable collections. A mutable collection can be updated or extended in place. This means you can change, add, or remove elements of a collection as a side effect. Immutable collections, by contrast, never change. You have still operations that simulate additions, removals, or updates, but those operations will in each case return a new collection and leave the old collection unchanged.

11.22. Sorting an Existing Map by Key or Value, Scala program to sort given map by key. import scala.collection.immutable.​ListMap. // Creating object. object GfG. {. // Main method. def main(args : Array[​String]). You can modify a mutable collection bound to a val in-place, though you can't reassign the val. you can't modify an immutable collection in-place, but if it's assigned to a var, you can reassign that var to a collection built from it by an operation such as +.

Comments
  • Related: stackoverflow.com/questions/4686184/… , but not really an answer (there was a newer question in '14 closed for that one .. not sure if '15 brings relevant changes)
  • Thanks for this. I think I'll use a reversed PriorityQueue, so the lowest-scored objects come out first on dequeue. That way if the number of objects per key goes far beyond the "top ten" that I'm keeping, I won't run afoul of that pitfall you mentioned.
  • If you want to convert your ArrayBuffer to an Array, then you could use Sorting.quicksort(myArray) to sort it in place without resorting to the Java library. But in my case I didn't want to convert my buffer to a fixed-size array, because I had more elements to add to it.