Scala Tuples, for when you just need a bag of things

This is an excerpt from the 1st edition of the Scala Cookbook (#ad) (partially modified for the internet). This is Recipe 10.27, “Scala Tuples, for When You Just Need a Bag of Things”

Problem

When writing a Scala application, you want to create a small collection of heterogeneous elements.

Solution

A tuple gives you a way to store a group of heterogeneous items in a container, which is useful in many situations.

Create a tuple by enclosing the desired elements between parentheses. This is a two- element tuple:

scala> val d = ("Amanda", 95)
d: (String, Int) = (Amanda,95)

Notice that it contains two different types. The following example shows a three-element tuple:

scala> case class Person(name: String)
defined class Person

scala> val t = (3, "Three", new Person("Al"))
t: (Int, java.lang.String, Person) = (3,Three,Person(Al))

You can access tuple elements using an underscore construct:

scala> t._1
res1: Int = 3

scala> t._2
res2: java.lang.String = Three

scala> t._3
res3: Person = Person(Al)

I often prefer to assign them to variables using pattern matching:

scala> val(x, y, z) = (3, "Three", new Person("Al"))
x: Int = 3
y: String = Three
z: Person = Person(Al)

A nice feature of this approach is that if you don’t want all of the elements from the tuple, just use the _ wildcard character in place of the elements you don’t want:

scala> val (x, y, _) = t
x: Int = 3
y: java.lang.String = Three

scala> val (x, _, _) = t
x: Int = 3

scala> val (x, _, z) = t
x: Int = 3
z: Person = Person(Al)

A two-element tuple is an instance of the Tuple2 class, and a tuple with three elements is an instance of the Tuple3 class. (More on this in the Discussion.) As shown earlier, you can create a Tuple2 like this:

scala> val a = ("AL", "Alabama")
a: (java.lang.String, java.lang.String) = (AL,Alabama)

You can also create it using these approaches:

scala> val b = "AL" -> "Alabama"
b: (java.lang.String, java.lang.String) = (AL,Alabama)

scala> val c = ("AL" -> "Alabama")
c: (java.lang.String, java.lang.String) = (AL,Alabama)

When you check the class created by these examples, you’ll find they’re all of type Tuple2:

scala> c.getClass
res0: java.lang.Class[_ <: (java.lang.String, java.lang.String)] =
      class scala.Tuple2

This syntax is very convenient for other uses, including the creation of maps:

val map = Map("AL" -> "Alabama")

Discussion

The tuple is an interesting construct. There is no single “Tuple” class; instead, the API defines tuple case classes from Tuple2 through Tuple22, meaning that you can have from 2 to 22 elements in a tuple.

A common use case for a tuple is returning multiple items from a method. See Recipe 5.5, “Defining a Method That Returns Multiple Items (Tuples)”, for an example of this.

Though a tuple isn’t a collection, you can treat a tuple as a collection when needed by creating an iterator:

scala> val x = ("AL" -> "Alabama")
x: (java.lang.String, java.lang.String) = (AL,Alabama)

scala> val it = x.productIterator
it: Iterator[Any] = non-empty iterator

scala> for (e <- it) println(e)
AL
Alabama

Be aware that like any other iterator, after it’s used once, it will be exhausted. Attempting to print the elements a second time yields no output:

scala> for (e <- it) println(e)
// no output here

Create a new iterator if you need to loop over the elements a second time.

You can also convert a tuple to a collection:

scala> val t = ("AL", "Alabama")
t: (String, String) = (AL,Alabama)

scala> t.productIterator.toArray
res0: Array[Any] = Array(AL, Alabama)

See Also

  • The Scala Tuple2 class
  • Recipe 5.5, “Defining a Method That Returns Multiple Items (Tuples)”