Start learning free

LESSON 264 OF 677 · TUPLES, SORTING & BUILT-INS

Tuples in Scala: Pairs, Unpacking and Returning Two Values

Lesson Read the full explanation

TL ; DR:

A tuple keeps a few values together, like a movie's title and year. Read them with ._1 and ._2, or unpack them into variables.


val movie = ("Frozen", 2013)   // a tuple
println(movie._1)              // Frozen
println(movie._2)              // 2013

val (title, year) = movie      // unpacking
println(s"$title $year")       // Frozen 2013


Full lesson:

Some values belong together. A movie has a title and a year. A point has an x and a y. A tuple keeps a few values like these in one variable.

  • ("Frozen", 2013) makes a tuple. Its type is (String, Int).
  • movie._1 is the first value, "Frozen". movie._2 is the second, 2013. They count from 1, not 0.

val (title, year) = movie unpacks the tuple into two new values. It works like for ((name, points) <- scores).

A function can return a tuple. Its return type is the tuple's type, like (Int, Int). Then return (a, b) builds it.

A tuple can't be changed. movie._2 = 2014 doesn't compile. To change a value, make a new tuple: (movie._1, 2014).

Printing a tuple shows its values: (Frozen,2013).


Your task

Rex the dog went for a long walk. pet holds his name and his age.

First, make splitTime return its tuple: the whole hours and the minutes left.

Then unpack pet into name and age.

Last, call splitTime(135). Unpack its result into hours and mins.

The code already prints the three lines.

Expected output:

Rex
Rex is 4
Rex walked 2 h 15 min
STEP 1 OF 3
    Ctrl + Enter to check

    SCALA · TUPLES, SORTING & BUILT-INS

    Tuples in Scala, explained

    What a tuple is

    Some values belong together. A pet has a name and an age. A point has an x and a y. A tuple keeps a few values like these in one variable, written in parentheses:

    val pet = ("Rex", 4)
    println(pet._1)
    println(pet._2)
    
    Rex
    4
    

    The type of pet is (String, Int). Each position has its own type, so a tuple can mix strings, numbers and anything else. The values are read with ._1 for the first and ._2 for the second. They count from 1, not from 0, which is different from ArrayBuffer indexes.

    Unpacking

    Writing pet._1 everywhere is hard to read. You can unpack the tuple into named values instead:

    val (name, age) = pet
    println(s"$name $age")
    
    Rex 4
    

    The names go in the same order as the values. The same pattern is what for ((name, points) <- scores) uses to unpack each pair in a loop. If the pattern has a different number of names than the tuple has values, the compiler rejects it. For a (String, Int) pair, a pattern with three names is a compile error, so the mistake shows up before the program runs.

    Returning two values

    A function returns one value, but that value can be a tuple. The return type is the tuple's type, such as (Int, Int):

    def splitTime(minutes: Int): (Int, Int) = {
        return (minutes / 60, minutes % 60)
    }
    

    Integer division gives the whole hours, and % gives the minutes left. splitTime(135) returns (2,15), and splitTime(59) returns (0,59). The caller can unpack the result straight away: val (hours, mins) = splitTime(135).

    More than two values

    A tuple can hold more than two values. val (a, b, c) = ("Rex", 4, true) works, and println(s"$a $b $c") prints Rex 4 true. The third value is ._3. Tuples are best for a few values that travel together briefly, such as a function's result. When a group of values has a meaning of its own, a class with named fields is easier to read than ._1 and ._2.

    Tuples can't change

    A tuple's values are fixed. This line does not compile:

    pet._2 = 5
    

    The compiler reports Reassignment to val _2. To get a different age, build a new tuple. (pet._1, 5) prints as (Rex,5), and pet itself stays (Rex,4).

    Printing a tuple shows its values in parentheses with a comma between them and no space, like (Rex,4).

    The exercise

    The task has three parts. First, make splitTime return its tuple. Next, unpack pet into name and age. Last, call splitTime(135) and unpack the result into hours and mins. Here is the finished code:

    class Solution {
        def splitTime(minutes: Int): (Int, Int) = {
            return (minutes / 60, minutes % 60)
        }
    
        def mainFunction(): Unit = {
            val pet = ("Rex", 4)
            println(pet._1)
    
            val (name, age) = pet
            println(s"$name is $age")
    
            val (hours, mins) = splitTime(135)
            println(s"$name walked $hours h $mins min")
        }
    }
    

    It prints:

    Rex
    Rex is 4
    Rex walked 2 h 15 min
    

    Each println uses names that the unpacking line above it creates, so every unpacking has to come before the line that prints those names. The last line also reuses name from the first unpacking.

    Common mistakes

    • Counting from 0: pet._0 doesn't exist. The first value is ._1.
    • Swapping names when unpacking: val (age, name) = pet gives age the string "Rex" and name the number 4.
    • Trying to assign to ._2. Build a new tuple instead.

    Key takeaways

    • A tuple groups a few values of possibly different types: ("Rex", 4) has type (String, Int).
    • Read values with ._1, ._2, or unpack them with val (a, b) = tuple.
    • A function returns several values by returning a tuple.
    • Tuples can't be changed; make a new one.
    Keep going with Scala500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free