Make the ArrayBuffer class your default mutable indexed sequence (Scala best practice)

This is an excerpt from the Scala Cookbook (partially re-worded for the internet). This is Recipe 10.8, “Make the Scala ArrayBuffer Class Your ‘Go To’ Mutable Indexed Sequence”

Problem

You want to use a general-purpose, mutable indexed sequence in your Scala applications.

Solution

Just as the Vector is the recommended “go to” class for immutable, indexed sequential collections, the Scala ArrayBuffer class is recommended as the general-purpose collections class for mutable, indexed sequential collections.

ArrayBuffer is an indexed sequential collection. Use ListBuffer if you prefer a linear sequential collection that is mutable. See Recipe 10.2, “How to Choose a Scala Collection Class”, for more information.

To use an ArrayBuffer, first import it:

import scala.collection.mutable.ArrayBuffer

You can then create an empty ArrayBuffer:

var fruits = ArrayBuffer[String]()
var ints = ArrayBuffer[Int]()

Or you can create an ArrayBuffer with initial elements:

var nums = ArrayBuffer(1, 2, 3)

Like other mutable collection classes, you add elements using the += and ++= methods:

scala> var nums = ArrayBuffer(1, 2, 3)
nums: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3)

// add one element
scala> nums += 4
res0: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 4)

// add two or more elements (method has a varargs parameter)
scala> nums += (5, 6)
res1: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 4, 5, 6)

// add elements from another collection
scala> nums ++= List(7, 8)
res2: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 4, 5, 6, 7, 8)

You remove elements with the -= and --= methods:

// remove one element
scala> nums -= 9
res3: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 4, 5, 6, 7, 8)

// remove two or more elements
scala> nums -= (7, 8)
res4: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 4, 5, 6)
// remove elements specified by another sequence

scala> nums --= Array(5, 6)
res5: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 4)

Discussion

Those are the methods I generally use to add and remove elements from an ArrayBuffer. However, there are many more:

val a = ArrayBuffer(1, 2, 3)         // ArrayBuffer(1, 2, 3)
a.append(4)                          // ArrayBuffer(1, 2, 3, 4)
a.append(5, 6)                       // ArrayBuffer(1, 2, 3, 4, 5, 6)
a.appendAll(Seq(7,8))                // ArrayBuffer(1, 2, 3, 4, 5, 6, 7, 8)
a.clear                              // ArrayBuffer()
val a = ArrayBuffer(9, 10)           // ArrayBuffer(9, 10)
a.insert(0, 8)                       // ArrayBuffer(8, 9, 10)
a.insert(0, 6, 7)                    // ArrayBuffer(6, 7, 8, 9, 10)
a.insertAll(0, Vector(4, 5))         // ArrayBuffer(4, 5, 6, 7, 8, 9, 10)
a.prepend(3)                         // ArrayBuffer(3, 4, 5, 6, 7, 8, 9, 10)
a.prepend(1, 2)                      // ArrayBuffer(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
a.prependAll(Array(0))               // ArrayBuffer(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val a = ArrayBuffer.range('a', 'h')  // ArrayBuffer(a, b, c, d, e, f, g)
a.remove(0)                          // ArrayBuffer(b, c, d, e, f, g)
a.remove(2, 3)                       // ArrayBuffer(b, c, g)
val a = ArrayBuffer.range('a', 'h')  // ArrayBuffer(a, b, c, d, e, f, g)
a.trimStart(2)                       // ArrayBuffer(c, d, e, f, g)
a.trimEnd(2)                         // ArrayBuffer(c, d, e)

See the Scaladoc for more methods that you can use to modify an ArrayBuffer.

The ArrayBuffer Scaladoc provides these details about ArrayBuffer performance: “Append, update, and random access take constant time (amortized time). Prepends and removes are linear in the buffer size.” The ArrayBuffer documentation also states, “array buffers are useful for efficiently building up a large collection whenever the new items are always added to the end.”

If you need a mutable sequential collection that works more like a List — i.e., a linear sequence rather than an indexed sequence — use ListBuffer instead of ArrayBuffer.

The Scala documentation on the ListBuffer states, “A ListBuffer is like an array buffer except that it uses a linked list internally instead of an array. If you plan to convert the buffer to a list once it is built up, use a list buffer instead of an array buffer.”