Start learning free

LESSON 114 OF 677 · ARRAYS I

Insert and Remove at a Position in Kotlin

Lesson Read the full explanation

TL ; DR:

add(i, x) puts x at index i. Use removeAt(i) to take out the item at index i. The other items move to make room or to close the gap.


val colors = mutableListOf("red", "green", "blue")

colors.add(1, "pink")
println(colors)   // [red, pink, green, blue]

colors.removeAt(0)
println(colors)   // [pink, green, blue]


Full lesson:

add(x) adds an item at the end. With an index first, add(i, x) puts x at index i instead. The items from index i on move one place to the right.

val pets = mutableListOf("Rex", "Milo")
pets.add(0, "Luna")
println(pets)   // [Luna, Rex, Milo]

You met removeAt(i) in the last lesson. It takes out the item at index i. The items after it move one place to the left. It also returns the item:

val first = pets.removeAt(0)
println(first)   // Luna
println(pets)    // [Rex, Milo]

Watch the indexes. After an insert or a removal, the items behind that spot have new indexes.

Don't mix up removeAt and remove. On a list of numbers, remove(2) takes out the value 2, not index 2.


Your task

pets holds the pets waiting at the vet, in order.

Bella has an appointment, so she goes second, at index 1. Then Milo goes home. Take him out of the line.

The code below prints how many pets wait once Bella is in. At the end, it prints the pets left.

Expected output:

4
Rex Bella Luna
STEP 1 OF 2
    Ctrl + Enter to check

    KOTLIN · ARRAYS I

    Array Insert Remove in Kotlin, explained

    Inserting with add(i, x)

    On a MutableList, add(x) puts an item at the end. Give it an index first and add(i, x) puts x at index i instead. Every item from index i on moves one place to the right to make room.

    val colors = mutableListOf("red", "green", "blue")
    colors.add(1, "pink")
    println(colors)
    
    [red, pink, green, blue]
    

    The valid indexes for add(i, x) run from 0 to the list's size, inclusive. colors.add(colors.size, "last") is the same as add("last"). Anything bigger throws an IndexOutOfBoundsException: on a list of two items, add(10, 1) fails with the message Index: 10, Size: 2.

    Removing with removeAt(i)

    removeAt(i) takes out the item at index i, and the items after it move one place to the left. It also returns the item it removed, so you can keep it:

    val gone = colors.removeAt(0)
    println(gone)
    println(colors)
    
    red
    [pink, green, blue]
    

    An index that doesn't exist throws an IndexOutOfBoundsException here too: removeAt(7) on a list of two items fails with Index 7 out of bounds for length 2.

    Traps

    • Indexes shift. After an insert or a removal, every item behind that spot has a new index. If you plan several changes, count again after each one.
    • removeAt is not remove. On a list of numbers, remove(2) takes out the first item equal to 2, not the item at index 2. It returns true or false to say whether it found one. With mutableListOf(5, 2, 9, 2), remove(2) leaves [5, 9, 2] and removeAt(2) then leaves [5, 9].
    • The list must be mutable. add and removeAt exist on MutableList, which is what mutableListOf builds. A plain List has neither.

    Common positions

    Two positions come up all the time. add(0, x) puts an item at the front, and removeAt(list.size - 1) takes out the last item. If you only know the value, find its index first with indexOf, which gives -1 when the value isn't there:

    val pets = mutableListOf("Rex", "Bella", "Luna")
    pets.add(0, "Zed")
    println(pets)
    pets.removeAt(pets.size - 1)
    println(pets)
    pets.removeAt(pets.indexOf("Bella"))
    println(pets)
    
    [Zed, Rex, Bella, Luna]
    [Zed, Rex, Bella]
    [Zed, Rex]
    

    If indexOf returns -1, removeAt(-1) throws, so check with in first when the value might be missing.

    Changing a list while looping over it

    Insert and remove change the list's size, so avoid calling them on a list while a for loop is walking through that same list. In for (x in nums) { if (x == 2) nums.removeAt(0) } on [1, 2, 3, 4], the loop throws a ConcurrentModificationException after the removal. Make the changes after the loop, or when you want to drop every item that matches a rule, use removeAll: big.removeAll { it % 2 == 0 } on [1, 2, 3, 4, 5, 6] leaves [1, 3, 5].

    Each insert or removal also has to shift the items behind the spot, so working near the front of a very long list does more work than working at the end. For the short lists in this chapter that makes no practical difference.

    The exercise

    pets starts as Rex, Milo, Luna. Bella has an appointment and goes second, at index 1, so the first step is pets.add(1, "Bella"). Now the list is Rex, Bella, Milo, Luna, which is why the code that prints the size shows 4. Milo moved to index 2, so the second step is pets.removeAt(2).

    val pets = mutableListOf("Rex", "Milo", "Luna")
    pets.add(1, "Bella")
    println(pets.size)
    pets.removeAt(2)
    println(pets[0] + " " + pets[1] + " " + pets[2])
    
    4
    Rex Bella Luna
    

    Using removeAt(1) here would take out Bella instead, because she now sits at index 1.

    Key takeaways

    • add(i, x) inserts x at index i and shifts the rest right.
    • removeAt(i) removes and returns the item at index i and shifts the rest left.
    • remove(x) looks for a value, so don't use it when you mean an index.
    • Recount the indexes after every change.
    Keep going with Kotlin500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free