Changing items in a List
The items of a List<T> are mutable. The same bracket syntax that reads an item also writes it: put the index on the left side of an assignment.
List<int> numbers = new List<int> {50, 40, 30};
numbers[0] = 15;
numbers[2] = -1;
Console.WriteLine(string.Join(", ", numbers)); // 15, 40, -1
Each assignment replaces the item at that index and leaves the others alone. The number of items doesn't change. C# lists have no set method; the indexer does that job.
Only existing positions can be assigned
The index has to refer to an item that is already in the list. Assigning to an index that doesn't exist throws an ArgumentOutOfRangeException, even for the next free position:
List<int> empty = new List<int>();
empty[0] = 1; // throws: the list has no index 0 yet
To add an item at the end, use Add, which a later lesson covers.
Compound assignment
Because numbers[1] is read and written like a variable, +=, -= and ++ work too. += reads the current value, adds to it and stores the result back in the same position.
Updating in a loop
Assignment and loops combine well. This loop adds 1 to every item of a list, one index at a time:
List<int> ages = new List<int> {14, 32, 50, 21};
for (int i = 0; i < ages.Count; i++) {
ages[i] += 1;
}
// ages is now 15, 33, 51, 22
Looping over the indexes is the way to change items in place. A foreach loop gives you a read-only copy of each value, so you can't assign to its loop variable. Changing a list while a foreach is reading it (by adding or removing items) throws an InvalidOperationException, while assigning through the indexer in a plain for loop is safe.
Also note that two variables can refer to the same list. If List<int> other = ages;, then other[0] = 0; changes what ages[0] shows, because there is only one list.
The exercise, step by step
The starter code gives you a List<string> called fruits and a List<int> called ages.
- Replace the first fruit. The first item is at index 0, so write
fruits[0] = "apple";. This overwrites"mango"with the new text. - Add 5 to the second age. The second item is at index 1, so write
ages[1] += 5;. The value 32 becomes 37.
List<string> fruits = new List<string>(new[] {"mango", "kiwi", "grapefruit"});
List<int> ages = new List<int>(new[] {14, 32, 50, 21});
fruits[0] = "apple";
ages[1] += 5;
Afterwards fruits contains apple, kiwi, grapefruit, and ages contains 14, 37, 50, 21.
The same idea applies to every update. ages[1] += 5 reads item 1, computes the sum and writes it back, so the previous value of 32 is replaced by 37. If you still need 32 afterwards, copy it to a variable before you update the item.
Each assignment is a single step that touches exactly one position, so the cost of an update doesn't depend on how long the list is.
Common mistakes
- Using a method from another language. Code ported from Java may call
set(0, 15). In C#, writenumbers[0] = 15;. - Wrong index. The first item is index 0 and the second is index 1.
- Assigning the wrong type.
ages[0] = "ten";doesn't compile, because the list holds ints. - Replacing instead of adding.
ages[1] = 5;sets the item to 5. Use+=to add to the existing value.
What happens to the old value
Assignment replaces the stored value, and the old one is gone unless you saved it first. To swap two items you need a temporary variable, because writing the first position would destroy the value you still need:
List<int> pair = new List<int> {1, 2};
int temp = pair[0];
pair[0] = pair[1];
pair[1] = temp;
// pair is now 2, 1
Things to try
After the exercise, try copying one item onto another with ages[0] = ages[3];. The list then starts with 21 because the right side is evaluated first and its value is stored in position 0. The list still has the same number of items. To see all the items at once, print the list with string.Join(", ", ages).
Key takeaways
- Update a list item with
list[index] = value;. - The index must already exist; assigning never grows the list.
- Compound operators such as
+=work on list items.