Start learning free

LESSON 116 OF 679 · ARRAYS I

Insert and Remove at a Position in Rust

Lesson Read the full explanation

TL ; DR:

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


let mut colors = vec!["red", "green", "blue"];

colors.insert(1, "pink");
// colors is now ["red", "pink", "green", "blue"]

colors.remove(0);
// colors is now ["pink", "green", "blue"]


Full lesson:

push adds an item at the end, and pop takes the last one away. For any other position, a Vec has insert and remove.

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

let mut pets = vec!["Rex", "Milo"];

pets.insert(0, "Luna");
// pets is now ["Luna", "Rex", "Milo"]

remove(i) takes out the item at index i. The items after it move one place to the left. It also returns the item:

let first = pets.remove(0);
// first is "Luna", and pets is now ["Rex", "Milo"]

Both change the Vec, so declare it with let mut.

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

An index past the end makes the program panic. One exception: insert accepts the length itself and adds the item at the end.


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

    RUST · ARRAYS I

    Array Insert Remove in Rust, explained

    What insert and remove do

    push adds an item at the end of a Vec and pop takes the last one away. For any other position, use insert and remove.

    insert(i, x) puts x at index i. The items from index i onward each move one place to the right to make room.

    remove(i) takes out the item at index i and returns it. The items after it move one place to the left to close the gap.

    let mut pets = vec!["Rex", "Milo"];
    
    pets.insert(0, "Luna");
    // pets is now ["Luna", "Rex", "Milo"]
    
    let first = pets.remove(0);
    // first is "Luna", and pets is now ["Rex", "Milo"]
    

    Both methods change the vector, so it must be declared with let mut. Without mut, the compiler stops with "cannot borrow pets as mutable, as it is not declared as mutable".

    Indexes move

    After an insert or a removal, every item behind that spot has a new index. Starting from ["a", "b", "c", "d"], calling remove(1) leaves ["a", "c", "d"], and now "c" sits at index 1, not 2. If you need an index after changing the vector, work it out again.

    Indexes past the end

    An index that is too large makes the program panic. With a vector of length 3, remove(3) stops with "removal index (is 3) should be < len (is 3)", because there is no item at index 3. insert(5, x) stops with "insertion index (is 5) should be <= len (is 3)".

    The one exception is that insert accepts the length itself: pets.insert(pets.len(), "Luna") adds at the end, just like push.

    Inserting in the middle and at the end

    Starting from [10, 20, 30], insert(1, 15) gives [10, 15, 20, 30], and remove(1) then returns 15 and leaves [10, 20, 30] again. Inserting at the length adds at the end: with ["Rex", "Milo", "Luna"], insert(line.len(), "Zed") gives ["Rex", "Milo", "Luna", "Zed"]. Inserting at index 0 puts the new item first.

    Shifting is not free: every item behind the spot has to move. For a short list that doesn't matter, and it is the price of keeping the items in order.

    The task, step by step

    The vector starts as ["Rex", "Milo", "Luna"]. Bella goes second in line, which is index 1, so the first step is pets.insert(1, "Bella"). Milo and Luna each move one place to the right, and the length is now 4.

    Next, Milo goes home. Because Bella came in, Milo has moved from index 1 to index 2, so the second step is pets.remove(2). The returned value is not needed, so it is simply ignored.

    let mut pets = vec!["Rex", "Milo", "Luna"];
    pets.insert(1, "Bella");
    println!("{}", pets.len());
    pets.remove(2);
    println!("{} {} {}", pets[0], pets[1], pets[2]);
    

    It prints:

    4
    Rex Bella Luna
    

    Why the order of the two steps matters

    The task does the insert first and the removal second, and the index of Milo depends on that order. Before Bella arrives, Milo is at index 1. After the insert, Bella is at index 1, Milo has moved to index 2, and Luna to index 3. Whenever you change a vector in several steps, say aloud what the vector looks like after each one, and read the next index from that picture.

    Common mistakes

    • Removing Milo with remove(1). That index was right before the insert; after it, index 1 holds Bella.
    • Writing the arguments the wrong way round. The index comes first and the value second: insert(1, "Bella").
    • Forgetting mut on the vector.

    Key takeaways

    • insert(i, x) adds at index i and shifts later items right.
    • remove(i) deletes index i, returns the item, and shifts later items left.
    • Both need a mut vector and panic on a bad index (except insert at the length).
    Keep going with Rust500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free