Start learning free

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

Pairs in Kotlin: first, second and Unpacking

Lesson Read the full explanation

TL ; DR:

A Pair keeps two values together, like a movie's title and year. Read them with .first and .second, or unpack them into variables.


val movie = Pair("Frozen", 2013)   // the same as "Frozen" to 2013
println(movie.first)               // Frozen
println(movie.second)              // 2013

val (title, year) = movie          // unpacking
println("$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. Kotlin keeps two values like these in a Pair.

  • Pair("Frozen", 2013) makes a pair. Its type is Pair<String, Int>.
  • "Frozen" to 2013 makes the same pair. You have used to in mutableMapOf("Ana" to 12).
  • movie.first is the first value, "Frozen". movie.second is the second, 2013.

val (title, year) = movie unpacks the pair into two new variables. It works like for ((name, points) in scores).

A function can return a pair. Its return type is the pair's type, like Pair<Int, Int>.

A pair can't be changed. first and second are vals. To change one, make a new pair: movie.copy(second = 2014).

Pair is a data class, so printing it 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 pair: 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

    KOTLIN · PAIRS, SORTING & BUILT-INS

    Tuples in Kotlin, explained

    What a Pair is

    Some values belong together: a pet's name and age, a point's x and y. Kotlin keeps two such values in a Pair. You make one with the constructor or with the to function, and both give the same pair:

    val pet = Pair("Rex", 4)
    val same = "Rex" to 4
    println(pet == same)
    
    true
    

    The type of pet is Pair<String, Int>: the first slot holds a String, the second an Int. The two slots can have different types.

    Reading and unpacking

    Read the slots with .first and .second. Or unpack the pair into two new variables in one line, with parentheses on the left of the =:

    val pet = Pair("Rex", 4)
    println(pet.first)
    println(pet.second)
    
    val (name, age) = pet
    println("$name is $age")
    
    Rex
    4
    Rex is 4
    

    The names are matched to the slots by position: the first name gets first, the second gets second. The names themselves are up to you, so pick ones that say what the values mean.

    Returning two values from a function

    A function returns one value, but that value can be a pair. The return type is the pair's type, here Pair<Int, Int>. The caller unpacks the result straight away:

    fun splitTime(minutes: Int): Pair<Int, Int> {
        return Pair(minutes / 60, minutes % 60)
    }
    
    val (hours, mins) = splitTime(135)
    println("$hours h $mins min")
    
    2 h 15 min
    

    Integer division drops the remainder, so 135 / 60 is 2 whole hours, and 135 % 60 is the 15 minutes left.

    A pair can't be changed

    first and second are vals, so pet.second = 5 doesn't compile. To get a different pair, make a new one with copy:

    val older = pet.copy(second = 5)
    println(older)
    println(pet)
    
    (Rex, 5)
    (Rex, 4)
    

    Pair is a data class, which is why printing it shows its values in parentheses, and why two pairs with equal values are equal with ==. The original pair stays as it was.

    Pairs in a list

    Pairs are often collected in a list, and a for loop can unpack each one as it goes, the same way:

    val pets = listOf("Rex" to 4, "Bella" to 7)
    for ((name, age) in pets) {
        println("$name is $age")
    }
    
    Rex is 4
    Bella is 7
    

    If you only need one of the two values, write an underscore for the other: val (_, age) = pets[1] gives age the value 7 and creates no variable for the name.

    For three values Kotlin has Triple, which works the same way with first, second and third: val (p, q, r) = Triple(1, "a", true) gives p = 1, q = "a" and r = true. For more than three values, a class of your own with named fields is clearer.

    The exercise

    The lesson's class has two tasks in mainFunction and one in splitTime:

    1. Make splitTime return the whole hours and the minutes left.
    2. Unpack pet into name and age.
    3. Call splitTime(135) and unpack the result into hours and mins.

    The finished code:

    class Solution {
        fun splitTime(minutes: Int): Pair<Int, Int> {
            return Pair(minutes / 60, minutes % 60)
        }
    
        fun mainFunction() {
            val pet = Pair("Rex", 4)
            println(pet.first)
    
            val (name, age) = pet
            println("$name is $age")
    
            val (hours, mins) = splitTime(135)
            println("$name walked $hours h $mins min")
        }
    }
    

    It prints the expected three lines:

    Rex
    Rex is 4
    Rex walked 2 h 15 min
    

    Notice that the last line uses name from step 2. Unpacking pet is what creates that variable, so the order of the steps matters.

    Common mistakes

    • Swapping the order when unpacking. val (age, name) = pet compiles, because the types are not checked against your names, but age now holds "Rex".
    • Forgetting the parentheses. val name, age = pet is not unpacking.
    • Trying to assign to first or second. Use copy instead.

    Key takeaways

    • Pair(a, b) and a to b make the same pair, of type Pair<A, B>.
    • Read the slots with .first and .second, or unpack with val (x, y) = pair.
    • A function can return a pair to give back two values at once.
    • A pair is read-only; copy makes a changed version.
    Keep going with Kotlin500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free