Start learning free

LESSON 112 OF 671 · ARRAYS I

Insert and Remove at a Position in Go

Lesson Read the full explanation

TL ; DR:

slices.Insert(s, i, x) puts x at index i. Use slices.Delete(s, i, i+1) to take out the item at index i. Both return the new slice, so assign it back.


colors := []string{"red", "green", "blue"}

colors = slices.Insert(colors, 1, "pink")
fmt.Println(colors)   // [red pink green blue]

colors = slices.Delete(colors, 0, 1)
fmt.Println(colors)   // [pink green blue]


Full lesson:

append adds an item at the end, and re-slicing takes the last one away. For any other position, Go's slices package has two helpers.

slices.Insert(s, i, x) puts x at index i. The items from index i on move one place to the right:

pets := []string{"Rex", "Milo"}
pets = slices.Insert(pets, 0, "Luna")
fmt.Println(pets)   // [Luna Rex Milo]

slices.Delete(s, i, j) takes out the items from index i up to, not including, j. So j = i + 1 takes out one item. The items after it move to the left:

pets = slices.Delete(pets, 0, 1)
fmt.Println(pets)   // [Rex Milo]

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

Like append, both return the new slice. Always assign the result back to the variable.

The slices package came with Go 1.21. The lesson's code already imports it for you.


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

    GO · ARRAYS I

    Array Insert Remove in Go, explained

    What the slices package gives you

    append adds an item at the end of a slice, and re-slicing can drop the last one. For any other position, Go's slices package has two helpers: slices.Insert and slices.Delete. The package arrived in Go 1.21, and the lesson's code already imports it for you.

    Inserting with slices.Insert

    slices.Insert(s, i, x) puts x at index i. Every item that was at index i or later moves one place to the right.

    pets := []string{"Rex", "Milo"}
    pets = slices.Insert(pets, 0, "Luna")
    fmt.Println(pets)   // [Luna Rex Milo]
    

    The index may be as large as len(s), which puts the new item at the very end:

    a := []int{1, 2, 3}
    a = slices.Insert(a, len(a), 4)
    fmt.Println(a)   // [1 2 3 4]
    

    Removing with slices.Delete

    slices.Delete(s, i, j) takes out the items from index i up to, but not including, j. To remove one item, use j = i + 1. The items after it move one place to the left.

    pets = slices.Delete(pets, 0, 1)
    fmt.Println(pets)   // [Rex Milo]
    

    A longer range works the same way. On []int{10, 20, 30, 40, 50}, slices.Delete(c, 1, 3) removes the items at indexes 1 and 2 and leaves [10 40 50].

    Always assign the result back

    Like append, both functions return the new slice, because the length changes. If you call slices.Insert(b, 1, 9) and throw the result away, b still has its old length and prints as [1 2 3]. Write pets = slices.Insert(...) every time.

    Both functions also panic when an index is out of range. Inserting into a two-item slice at index 5 stops the program with slice bounds out of range [5:2].

    The old slice is not safe to reuse

    These helpers work in place on the slice's memory. After b := slices.Delete(a, 0, 1) on []int{1, 2, 3, 4}, b is [2 3 4], but a now prints as [2 3 4 0]: its items moved left and the freed last place was cleared. So keep using the variable you assigned the result to, and don't rely on the old one. To keep the original, delete from a copy: slices.Delete(slices.Clone(c), 0, 1) leaves c as [1 2 3 4].

    Removing a value instead of a position

    When you know the value but not the index, find it first with slices.Index, which returns -1 when the value is missing, and delete only if it was found:

    names := []string{"Rex", "Milo", "Luna"}
    i := slices.Index(names, "Milo")
    if i != -1 {
        names = slices.Delete(names, i, i+1)
    }
    fmt.Println(names)   // [Rex Luna]
    

    slices.Insert also accepts several values at once: slices.Insert(e, 1, 2, 3, 4) on []int{1, 5} gives [1 2 3 4 5].

    Indexes shift

    Suppose a line holds Rex, Milo, Luna. After Bella is inserted at index 1 it holds Rex, Bella, Milo, Luna: Milo moved from index 1 to index 2, and Luna from 2 to 3. Anything that remembered the old indexes is now wrong. When you do several changes in a row, work out each index from the slice as it is at that moment, not as it was at the start.

    After an insert or a removal, the items behind that spot have new indexes. That is the main trap in the task below.

    The task: the vet's waiting line

    pets starts as Rex, Milo, Luna. Bella has an appointment, so she goes second, at index 1. Then Milo goes home. The code prints how many pets wait once Bella is in, and then the pets left.

    1. Insert Bella at index 1 and assign the result back. The line is now Rex, Bella, Milo, Luna, so len(pets) is 4.
    2. Milo is no longer at index 1: Bella pushed him to index 2. Remove him with slices.Delete(pets, 2, 3).
    pets := []string{"Rex", "Milo", "Luna"}
    pets = slices.Insert(pets, 1, "Bella")
    fmt.Println(len(pets))
    pets = slices.Delete(pets, 2, 3)
    fmt.Println(pets[0], pets[1], pets[2])
    

    The output is:

    4
    Rex Bella Luna
    

    Using the old index by mistake, slices.Delete(pets, 1, 2), would remove Bella instead and leave [Rex Milo Luna].

    Key takeaways

    • slices.Insert(s, i, x) puts x at index i and shifts the rest right.
    • slices.Delete(s, i, i+1) removes the item at index i; the end index is not included.
    • Assign the returned slice back to the variable.
    • Recompute indexes after every change.
    Keep going with Go500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free