On this page26 sections
- Prerequisites
- Connection With Previous Lectures
- Learning Objectives
- 1. A List That Can Change Size
- 2. add — One Element at the End
- 3. addAll — Many Elements at the End
- 4. insert — One Element at a Position
- 5. insertAll — Many Elements at a Position
- 6. remove — Remove by Value
- 7. removeAt and removeLast — Remove by Position
- 8. removeRange — Remove a Block
- 9. removeWhere — Remove Everything That Matches
- 10. clear — Remove Everything
- 11. Fixed-Length Lists
- 12. final Lists vs const Lists
- 13. Don't Change a List While Looping Over It
- 14. A Real-World Example
- Code Examples
- Common Beginner Mistakes
- Best Practices
- Mini Challenge
- Practice Questions
- Practice Answers
- Quick Revision
- Key Takeaways
- What's Next?
Lecture 41 — Adding & Removing Elements
| Category | 7 — Lists |
| Lecture | 041 of 140 |
| Estimated video length | 11 min |
| Target | Dart 3.12.2 |
| Level | Beginner |
So far a list kept the values it was born with. With
add,insert,removeand their relatives, a list grows and shrinks while the program runs.
Contents
Prerequisites · Connection · Objectives · Lesson · Code Examples · Common Mistakes · Best Practices · Mini Challenge · Practice Questions · Answers · Takeaways
Every error message in this lecture is real. Each one was produced by running the code shown on Dart 3.12.2, so you will recognize it when you meet it yourself.
Prerequisites
Students should already understand, from Lectures 001–040:
finalandconstvariables (Lecture 006)for-inloops (Lecture 027)- named arguments (Lecture 033) and arrow / anonymous functions (Lecture 034)
- creating lists,
List<int>,length, andisEmpty(Lecture 039) - reading and changing elements by index, and the
RangeError(Lecture 040)
Connection With Previous Lectures
In Lecture 040 we changed the values inside a list:
marks[1] = 95;But the list still had exactly the same number of elements. A shopping cart gets new items, a
class gets a new student, a finished task leaves the to-do list. Writing marks[3] = 70 on a
three-element list does not add a fourth element — it crashes with a RangeError. We need
operations that change the size of the list.
Learning Objectives
By the end of this lecture you will be able to:
- Add one element with
addand many withaddAll - Put elements at a chosen position with
insertandinsertAll - Remove elements by value, by index, from the end, or by range
- Remove every element that matches a condition with
removeWhere - Empty a list with
clear - Tell a growable list from a fixed-length list
- Explain why a
finallist can still change but aconstlist cannot - Avoid changing a list while a
for-inloop is walking through it
1. A List That Can Change Size
A list written with square brackets is growable: its length changes as you add and remove elements.
Analogy — think of a shopping list on a notepad. You can write a new line at the bottom, squeeze one in between, or cross one out. The notepad is the same; the number of lines changes.
void main() {
var cart = ['Milk', 'Bread'];
print(cart.length);
cart.add('Eggs');
print(cart.length);
}2
32. add — One Element at the End
add puts one element after the last one.
void main() {
var marks = [85, 92];
marks.add(78);
marks.add(64);
print(marks);
}[85, 92, 78, 64]The new element must match the list's type. marks is a List<int>, so marks.add('70') is
rejected before the program runs.
3. addAll — Many Elements at the End
addAll takes another list and adds all of its elements, in order.
void main() {
var names = ['Ali', 'Sara'];
names.addAll(['Zayan', 'Hina']);
print(names);
}[Ali, Sara, Zayan, Hina]4. insert — One Element at a Position
insert(index, value) puts the value at that index and pushes everything after it one
place to the right.
void main() {
var queue = ['Ali', 'Sara', 'Zayan'];
queue.insert(1, 'Hina');
print(queue);
}[Ali, Hina, Sara, Zayan]insert(0, …) adds at the front. The index may also equal length, which adds at the end.
5. insertAll — Many Elements at a Position
void main() {
var numbers = [1, 5];
numbers.insertAll(1, [2, 3, 4]);
print(numbers);
}[1, 2, 3, 4, 5]6. remove — Remove by Value
remove(value) deletes the first element equal to the value. It returns true if it found
one and false if it did not.
void main() {
var fruits = ['apple', 'mango', 'apple'];
print(fruits.remove('apple'));
print(fruits);
print(fruits.remove('banana'));
}true
[mango, apple]
falseOnly the first 'apple' went. Asking for a missing value is not an error — you just get
false.
7. removeAt and removeLast — Remove by Position
removeAt(index) deletes the element at that index; removeLast() deletes the last one. Both
return the element they removed, so you can keep it.
void main() {
var tasks = ['wash', 'cook', 'study', 'sleep'];
var done = tasks.removeAt(1);
var last = tasks.removeLast();
print(done);
print(last);
print(tasks);
}cook
sleep
[wash, study]A wrong index gives the same RangeError you met in Lecture 040.
8. removeRange — Remove a Block
removeRange(start, end) deletes from start up to, but not including, end.
void main() {
var scores = [10, 20, 30, 40, 50];
scores.removeRange(1, 3);
print(scores);
}[10, 40, 50]Indexes 1 and 2 (20 and 30) went; index 3 stayed. end - start is how many elements
disappear.
9. removeWhere — Remove Everything That Matches
removeWhere takes a function — the anonymous functions from Lecture 034. Dart calls it
once for each element and removes every element for which it returns true.
void main() {
var marks = [85, 42, 78, 39, 91];
marks.removeWhere((mark) => mark < 50);
print(marks);
}[85, 78, 91]Read (mark) => mark < 50 as "remove a mark if it is below 50". Unlike remove, this removes
all matches, not just the first.
10. clear — Remove Everything
void main() {
var cart = ['Milk', 'Bread', 'Eggs'];
cart.clear();
print(cart);
print(cart.isEmpty);
}[]
trueThe list still exists and can be filled again; it is just empty.
11. Fixed-Length Lists
List.filled(length, value) creates a list of a set size, every slot holding the same value.
That list is fixed-length: you may change its elements, but not its size.
void main() {
var seats = List.filled(3, 0);
seats[1] = 7;
print(seats);
}[0, 7, 0]Trying to grow it compiles, then stops the running program:
void main() {
var seats = List.filled(3, 0);
seats.add(5); // ✗ fixed-length
}Unhandled exception:
Unsupported operation: Cannot add to a fixed-length listPass the named argument growable: true when you want the filled list to grow:
void main() {
var seats = List.filled(3, 0, growable: true);
seats.add(5);
print(seats);
}[0, 0, 0, 5]12. final Lists vs const Lists
final stops the variable from pointing at a different list. The list itself can still
change:
void main() {
final names = ['Ali'];
names.add('Sara'); // ✓ changing the list
print(names);
}[Ali, Sara]Writing names = ['Sara']; would fail with Error: Can't assign to the final variable 'names'.
A const list goes further — nothing about it can change:
void main() {
const marks = [85, 92];
marks.add(70); // ✗ const list
}Unhandled exception:
Unsupported operation: Cannot add to an unmodifiable listWe will study const lists and other unmodifiable collections in Lecture 046 — Collection
Features. For now: use final for a list you will add to.
13. Don't Change a List While Looping Over It
A for-in loop walks the list one element at a time. If the loop body adds or removes
elements, Dart stops the program:
void main() {
var marks = [85, 92, 78];
for (final mark in marks) {
if (mark < 80) {
marks.remove(mark); // ✗ changes the list mid-loop
}
}
print(marks);
}Unhandled exception:
Concurrent modification during iteration: Instance(length:2) of '_GrowableList'.Dart calls this a ConcurrentModificationError: the list changed under the loop's feet. The
fix is to let one method do the whole job:
void main() {
var marks = [85, 92, 78];
marks.removeWhere((mark) => mark < 80);
print(marks);
}[85, 92]14. A Real-World Example
void main() {
final cart = <String>[];
cart.add('Milk');
cart.addAll(['Bread', 'Eggs', 'Tea']);
cart.insert(0, 'Rice');
cart.remove('Eggs');
var last = cart.removeLast();
cart.removeWhere((item) => item.startsWith('B'));
print('Took out: $last');
print('Cart: $cart');
print('Items: ${cart.length}');
}Took out: Tea
Cart: [Rice, Milk]
Items: 2The cart starts empty, grows to five items, then shrinks: 'Eggs' by value, 'Tea' from the
end, and every item starting with B. final keeps cart pointing at the same list the whole
time.
Code Examples
Example 1 — Building a List Step by Step
void main() {
var colors = <String>[];
colors.add('red');
colors.add('green');
colors.add('blue');
print(colors);
}[red, green, blue]Example 2 — Joining Two Groups
void main() {
var morning = ['Ali', 'Sara'];
var evening = ['Zayan', 'Hina'];
morning.addAll(evening);
print(morning);
print(evening);
}[Ali, Sara, Zayan, Hina]
[Zayan, Hina]addAll copies the elements; evening is unchanged.
Example 3 — Front, Middle, End
void main() {
var letters = ['b', 'd'];
letters.insert(0, 'a');
letters.insert(2, 'c');
letters.insert(letters.length, 'e');
print(letters);
}[a, b, c, d, e]Example 4 — remove Reports Success
void main() {
var guests = ['Ali', 'Sara'];
var removed = guests.remove('Zayan');
print(removed ? 'Removed' : 'Not on the list');
}Not on the listExample 5 — Undo the Last Step
void main() {
var history = ['open', 'type', 'delete'];
var undone = history.removeLast();
print('Undo: $undone');
print(history);
}Undo: delete
[open, type]Example 6 — Trim the Ends
void main() {
var readings = [0, 12, 15, 14, 0];
readings.removeAt(0);
readings.removeLast();
print(readings);
}[12, 15, 14]Example 7 — Student Marks: Drop the Failing Marks
void main() {
final marks = [72, 45, 88, 30, 65];
marks.removeWhere((mark) => mark < 50);
print('Passing marks: $marks');
print('Count: ${marks.length}');
}Passing marks: [72, 88, 65]
Count: 3How it works
- The anonymous function returns
truefor45and30, so those two are removed. finalis fine: the list changes, the variable does not.
Example 8 — Shopping Total After Removing an Item
void main() {
final prices = [450, 1200, 300];
prices.add(800);
prices.remove(1200);
var total = 0;
for (final price in prices) {
total += price;
}
print('Prices: $prices');
print('Total: $total');
}Prices: [450, 300, 800]
Total: 1550How it works
- The list changes first (
add,remove) — before the loop starts. - The loop only reads, so no concurrent modification can happen.
Example 9 — Bank Balance: Recent Transactions Only
void main() {
final transactions = [500, -200, 1000, -50, 300, -120];
transactions.removeRange(0, 3);
var balance = 0;
for (final amount in transactions) {
balance += amount;
}
print('Recent: $transactions');
print('Change: $balance');
}Recent: [-50, 300, -120]
Change: 130How it works
removeRange(0, 3)removes the three oldest transactions — indexes0,1,2.- The loop adds up what is left:
-50 + 300 - 120is130.
Example 10 — Temperature Log With a Fixed Week
void main() {
var week = List.filled(7, 0.0);
week[0] = 21.5;
week[1] = 24.0;
week[6] = 19.0;
print(week);
print('Days: ${week.length}');
}[21.5, 24.0, 0.0, 0.0, 0.0, 0.0, 19.0]
Days: 7How it works
- A week always has seven days, so a fixed-length list fits: values change, the size never does.
- Every slot starts at
0.0; filling a slot uses an index, notadd.
Common Beginner Mistakes
1. Removing inside a for-in loop
for (final mark in marks) {
if (mark < 80) marks.remove(mark);
}Unhandled exception:
Concurrent modification during iteration: Instance(length:2) of '_GrowableList'.Use removeWhere instead (see section 13).
2. Expecting remove to delete every copy
['apple', 'mango', 'apple'].remove('apple') deletes only the first 'apple'. To delete all,
use removeWhere((fruit) => fruit == 'apple').
3. Passing a single value to addAll
void main() {
var marks = [85, 92];
marks.addAll(70); // ✗ needs a list
}Error: The argument type 'int' can't be assigned to the parameter type 'Iterable<int>'.Use add(70), or addAll([70]). Iterable is the family that lists belong to; we meet it
in Lecture 046.
4. Using the result of add
void main() {
var marks = [85, 92];
var result = marks.add(70); // add returns nothing (void)
print(result); // ✗ using that nothing is the error
}Error: This expression has type 'void' and can't be used.add changes the list and gives nothing back. Dart reports the error on the line that
uses result. Print the list instead.
5. Removing from an empty list
void main() {
var names = <String>[];
names.removeLast(); // ✗ nothing to remove
}Unhandled exception:
RangeError (length): Invalid value: Valid value range is empty: -1Check isNotEmpty first.
6. Forgetting that removeRange excludes end
removeRange(1, 3) removes two elements (indexes 1 and 2), not three.
7. Adding to a fixed-length or const list
Both compile and then crash with Unsupported operation. Use a bracket list, or
List.filled(…, growable: true).
Best Practices
- Declare a list you will add to with
final, notconst. - Use
addfor one element andaddAllfor a group. - Prefer
removeWhereover a hand-written loop when removing by condition. - Never add or remove inside a
for-inloop over the same list. - Keep the value returned by
removeAt/removeLastwhen you need it. - Check
isNotEmptybeforeremoveLast. - Use
List.filledonly when the size is truly fixed.
Mini Challenge
Start with the class list ['Ali', 'Sara']. Add 'Zayan' at the end, put 'Hina' at the
front, remove 'Sara', then print the list and its length.
[Hina, Ali, Zayan]
Students: 3Try it yourself before opening the solution.
Show solution
void main() {
final students = ['Ali', 'Sara'];
students.add('Zayan');
students.insert(0, 'Hina');
students.remove('Sara');
print(students);
print('Students: ${students.length}');
}[Hina, Ali, Zayan]
Students: 3Practice Questions
Work through these in order — they run from beginner to application to challenge.
Beginner
- Start with
[1, 2, 3], add4, and print the list. - Start with
['Ali'], add'Sara'and'Zayan'with one call, and print the list. - Start with
[10, 30], insert20between them, and print the list.
Application
- Start with
['red', 'green', 'blue']. Remove'green'by value and print the result ofremove, then the list. - Start with
['a', 'b', 'c', 'd']. Remove the element at index2, print the removed element, then the list. - Start with
[5, 10, 15, 20, 25, 30]. Remove the middle two elements (15and20) withremoveRangeand print the list. - Start with
[3, 8, 12, 5, 20]. Remove every number greater than9and print the list. - Create a fixed-length list of four
falsevalues, set index2totrue, and print it.
Challenge
- Start with
final cart = ['Milk', 'Bread', 'Eggs', 'Butter']. Remove the last item and keep it, remove every item containing the lettere, then printRemoved: …andCart: …. - Start with
final temps = [18.5, -2.0, 25.0, 99.0, 21.0]. Remove readings below0or above50, then add22.5, and print the list and the average of its values.
Practice Answers
Question 1 — Solution
void main() {
var numbers = [1, 2, 3];
numbers.add(4);
print(numbers);
}[1, 2, 3, 4]Question 2 — Solution
void main() {
var names = ['Ali'];
names.addAll(['Sara', 'Zayan']);
print(names);
}[Ali, Sara, Zayan]Question 3 — Solution
void main() {
var numbers = [10, 30];
numbers.insert(1, 20);
print(numbers);
}[10, 20, 30]Question 4 — Solution
void main() {
var colors = ['red', 'green', 'blue'];
print(colors.remove('green'));
print(colors);
}true
[red, blue]Question 5 — Solution
void main() {
var letters = ['a', 'b', 'c', 'd'];
var removed = letters.removeAt(2);
print(removed);
print(letters);
}c
[a, b, d]Question 6 — Solution
void main() {
var numbers = [5, 10, 15, 20, 25, 30];
numbers.removeRange(2, 4);
print(numbers);
}[5, 10, 25, 30]15 is at index 2 and 20 at index 3, so the end is 4.
Question 7 — Solution
void main() {
var numbers = [3, 8, 12, 5, 20];
numbers.removeWhere((n) => n > 9);
print(numbers);
}[3, 8, 5]Question 8 — Solution
void main() {
var flags = List.filled(4, false);
flags[2] = true;
print(flags);
}[false, false, true, false]Question 9 — Solution
void main() {
final cart = ['Milk', 'Bread', 'Eggs', 'Butter'];
var removed = cart.removeLast();
cart.removeWhere((item) => item.contains('e'));
print('Removed: $removed');
print('Cart: $cart');
}Removed: Butter
Cart: [Milk, Eggs]contains('e') is case-sensitive: 'Bread' has a small e, but 'Eggs' only has a capital
E, so it stays.
Question 10 — Solution
void main() {
final temps = [18.5, -2.0, 25.0, 99.0, 21.0];
temps.removeWhere((t) => t < 0 || t > 50);
temps.add(22.5);
var sum = 0.0;
for (final t in temps) {
sum += t;
}
print(temps);
print('Average: ${sum / temps.length}');
}[18.5, 25.0, 21.0, 22.5]
Average: 21.75The condition uses || from Lecture 019, so a reading is removed if either side is true.
Quick Revision
- What is the difference between
addandaddAll? - What does
insert(0, x)do? - What does
removereturn, and how many copies does it delete? - Which two methods return the element they removed?
- Is the
endindex ofremoveRangeremoved? - What does the function passed to
removeWheredecide? - Why does
List.filled(3, 0).add(1)crash? - Why can a
finallist grow while aconstlist cannot?
Key Takeaways
- A bracket list is growable: its length changes as you add and remove.
add/addAllappend at the end;insert/insertAllput elements at an index.remove(value)deletes the first match and returnstrueorfalse.removeAt(index)andremoveLast()delete by position and return the removed element.removeRange(start, end)deletes fromstartup to, but not including,end.removeWhereremoves every element for which its function returnstrue.clearempties the list; the list itself remains.List.filledmakes a fixed-length list unless you passgrowable: true.- A
finallist can change its contents; aconstlist cannot. - Adding or removing inside a
for-inover the same list throws aConcurrentModificationError.
What's Next?
Lecture 42 — List Searching. Now that a list can grow and shrink, we need to find things in
it: checking whether a value is there with contains, finding its position with indexOf, and
picking out the first element that matches a condition.