Adding and removing in the middle
An ArrayBuffer is Scala's growable list. += adds an item at the end, but sometimes an item has to go somewhere else, or leave from somewhere else. Two methods do that, and both take an index first:
insert(i, x)putsxat indexi. The items from indexion move one place to the right.remove(i)takes out the item at indexi. The items after it move one place to the left, closing the gap.
val colors = scala.collection.mutable.ArrayBuffer("red", "green", "blue")
colors.insert(1, "pink")
println(colors) // ArrayBuffer(red, pink, green, blue)
colors.remove(0)
println(colors) // ArrayBuffer(pink, green, blue)
Both methods change the buffer itself. They don't build a new one.
remove also returns the item
remove(i) hands back the item it took out, so you can keep it:
val pets = scala.collection.mutable.ArrayBuffer("Rex", "Milo")
pets.insert(0, "Luna")
println(pets) // ArrayBuffer(Luna, Rex, Milo)
val first = pets.remove(0)
println(first) // Luna
println(pets) // ArrayBuffer(Rex, Milo)
If you don't need the item, ignore the result, as the lesson's task does.
Indexes shift
After an insert or a removal, every item behind that spot has a new index. This is the usual source of mistakes. In Rex, Milo, Luna, Milo is at index 1. Once Bella is inserted at index 1, Milo is at index 2. A remove(1) written from memory of the old list would take out Bella.
The end is a valid index for insert
You can insert at index size, which puts the item at the end. A larger index is an error: inserting at index 10 into a three-item buffer throws an IndexOutOfBoundsException. So does remove(5) on a buffer that has fewer than six items.
An index is not a value
-= also removes, but it takes a value, not an index. The two look alike on a buffer of numbers, and they give different results:
val nums = scala.collection.mutable.ArrayBuffer(10, 20, 30, 40)
nums.remove(1) // index 1: removes 20
println(nums) // ArrayBuffer(10, 30, 40)
nums -= 10 // value 10: removes the item that equals 10
println(nums) // ArrayBuffer(30, 40)
With strings, pets -= "Milo" removes the first item equal to "Milo" and does nothing if there is none.
Why the shifting matters
An ArrayBuffer keeps its items in one row, numbered from 0 with no gaps. When you insert, the buffer has to open a gap, so every item from that index on slides one place right. When you remove, it closes the gap, so every item behind slides one place left. That is why a long buffer is slower to change near its front than near its end, and why the numbers you had in mind a moment ago can be wrong a line later. When a task has several steps, work out the buffer after each call and read the new indexes from that.
The task
The vet's line starts as Rex, Milo, Luna. Bella has an appointment and goes second, at index 1. Then Milo goes home. The code prints how many pets wait once Bella is in, and at the end it prints the pets left.
- Call
pets.insert(1, "Bella"). The line is nowRex, Bella, Milo, Luna. - Milo moved from index 1 to index 2, so call
pets.remove(2).
val pets = scala.collection.mutable.ArrayBuffer("Rex", "Milo", "Luna")
pets.insert(1, "Bella")
println(pets.size)
pets.remove(2)
println(pets(0) + " " + pets(1) + " " + pets(2))
It prints:
4
Rex Bella Luna
Key takeaways
insert(i, x)addsxat indexiand shifts the rest to the right; the index comes first.remove(i)takes out the item at indexi, shifts the rest to the left and returns the item.- After either call, recompute the indexes of the items behind that spot.
-=removes by value;removeremoves by index.
