Make the Scala Vector class your default immutable sequence

This is an excerpt from the Scala Cookbook. This is Recipe 10.7, “Make the Scala Vector Class Your ‘Go To’ Immutable Sequence.”

Problem

You want a fast, general-purpose, immutable, sequential collection type for your Scala applications.

Solution

The Vector class was introduced in Scala 2.8 and is now considered to be the “go to,” general-purpose immutable sequential data structure.

Vector is an indexed, immutable sequential collection. Use a Scala List if you need to work with a linear, immutable sequential collection. See Recipe 10.2, “How to choose a Scala Collection Class”, for more details.

Create and use a Vector just like other immutable, indexed sequences. You can create them and access elements efficiently by index:

scala> val v = Vector("a", "b", "c")
v: scala.collection.immutable.Vector[java.lang.String] = Vector(a, b, c)

scala> v(0)
res0: java.lang.String = a

Adding (appending and prepending) items

You can’t modify a vector, so you “add” elements to an existing vector as you assign the result to a new variable:

scala> val a = Vector(1, 2, 3)
a: scala.collection.immutable.Vector[Int] = Vector(1, 2, 3)

scala> val b = a ++ Vector(4, 5)
b: scala.collection.immutable.Vector[Int] = Vector(1, 2, 3, 4, 5)

Append a single item to a Vector with :+

scala> val v = Vector(1, 2, 3)
v: scala.collection.immutable.Vector[Int] = Vector(1, 2, 3)

scala> val a = v :+ 4
a: scala.collection.immutable.Vector[Int] = Vector(1, 2, 3, 4)

Prepend an item to a vector with +:

scala> val v = Vector(1, 2, 3)
v: scala.collection.immutable.Vector[Int] = Vector(1, 2, 3)

scala> val a = 0 +: v
a: scala.collection.immutable.Vector[Int] = Vector(0, 1, 2, 3)

Replacing, filtering

Use the updated method to replace one element in a Vector while assigning the result to a new variable:

scala> val c = b.updated(0, "x")
c: scala.collection.immutable.Vector[java.lang.String] = Vector(x, b, c)

You can also use all the usual filtering methods to get just the elements you want out of a vector:

scala> val a = Vector(1, 2, 3, 4, 5)
a: scala.collection.immutable.Vector[Int] = Vector(1, 2, 3, 4, 5)

scala> val b = a.take(2)
b: scala.collection.immutable.Vector[Int] = Vector(1, 2)

scala> val c = a.filter(_ > 2)
c: scala.collection.immutable.Vector[Int] = Vector(3, 4, 5)

In those examples, I created each variable as a val and assigned the output to a new variable just to be clear, but you can also declare your variable as a var and reassign the result back to the same variable:

scala> var a = Vector(1, 2, 3)
a: scala.collection.immutable.Vector[Int] = Vector(1, 2, 3)

scala> a = a ++ Vector(4, 5)
a: scala.collection.immutable.Vector[Int] = Vector(1, 2, 3, 4, 5)

Discussion

Using the Vector class as your default immutable sequence is considered to be a Scala “best practice.” The “concrete, immutable collections classes” page on the scala-lang.org website states, “Vector is a collection type (introduced in Scala 2.8) that addresses the inefficiency for random access on lists. Vectors allow accessing any element of the list in ‘effectively’ constant time ... Because vectors strike a good balance between fast random selections and fast random functional updates, they are currently the default implementation of immutable indexed sequences...”

In his book, Scala In Depth (Manning Publications), Joshua Suereth offers the rule, “When in Doubt, Use Vector.” He writes, “Vector is the most flexible, efficient collection in the Scala collections library.”

As noted in Recipe 10.1, if you create an instance of an IndexedSeq, Scala returns a Vector:

scala> val x = IndexedSeq(1,2,3)
x: IndexedSeq[Int] = Vector(1, 2, 3)

As a result, I’ve seen some developers create an IndexedSeq in their code, rather than a Vector, to be more generic and to allow for potential future changes.

See Also