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

This is an excerpt from the 1st edition of the Scala Cookbook (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)”