Loops: for, while, do-while & for-in
Why Do We Need Loops?
Imagine you need to print "Hello" 100 times, or process every item in a list of 1,000 products. Writing each line manually would be absurd. Loops let you repeat a block of code as many times as needed -- either a fixed number of times, or until a condition becomes false. Loops are one of the most fundamental tools in every programming language.
The for Loop
The for loop is the most common loop in Dart. It has three parts: initialization (runs once), a condition (checked before each iteration), and an update (runs after each iteration).
Basic for Loop
void main() {
// Print numbers 1 through 5
for (int i = 1; i <= 5; i++) {
print(i);
}
// Output: 1 2 3 4 5
// Count by twos
for (int i = 0; i <= 10; i += 2) {
print(i);
}
// Output: 0 2 4 6 8 10
// Count backwards
for (int i = 5; i >= 1; i--) {
print('Countdown: $i');
}
// Output: Countdown: 5 Countdown: 4 ... Countdown: 1
}
i is scoped to the for loop. It does not exist outside the loop body. This prevents accidental reuse and keeps your code clean.Looping Through Strings
You can use a for loop to iterate over each character of a string by using the string’s length property and index notation:
String Iteration
void main() {
String word = 'Dart';
for (int i = 0; i < word.length; i++) {
print('Character $i: ${word[i]}');
}
// Output:
// Character 0: D
// Character 1: a
// Character 2: r
// Character 3: t
}
The while Loop
The while loop repeats a block of code as long as a condition is true. Use it when you don’t know in advance how many iterations you need.
Basic while Loop
void main() {
int count = 1;
while (count <= 5) {
print('Count: $count');
count++; // Don't forget this! Without it, the loop runs forever.
}
// Output: Count: 1 Count: 2 Count: 3 Count: 4 Count: 5
// Practical example: divide until less than 1
double value = 100.0;
int divisions = 0;
while (value >= 1) {
value /= 2;
divisions++;
}
print('Divided $divisions times. Final value: ${value.toStringAsFixed(4)}');
// Output: Divided 7 times. Final value: 0.7813
}
false, you get an infinite loop and your program will hang or crash. Always ensure that something inside the loop changes the condition toward false.The do-while Loop
The do-while loop is similar to while, but with one key difference: it always executes the body at least once before checking the condition. The condition is checked after each iteration.
do-while vs while
void main() {
// This while loop runs 0 times (condition is false immediately)
int x = 10;
while (x < 5) {
print('while: $x'); // Never prints
x++;
}
// This do-while loop runs 1 time (body executes before condition check)
int y = 10;
do {
print('do-while: $y'); // Prints: do-while: 10
y++;
} while (y < 5);
}
Practical do-while: Input Validation Simulation
void main() {
// Simulate a menu that must show at least once
List<String> simulatedInputs = ['invalid', 'wrong', 'quit'];
int attempt = 0;
do {
String input = simulatedInputs[attempt];
print('Attempt ${attempt + 1}: You entered "$input"');
if (input == 'quit') {
print('Goodbye!');
break;
}
print('Invalid input, try again.');
attempt++;
} while (attempt < simulatedInputs.length);
}
while loop instead.The for-in Loop
The for-in loop is designed for iterating over collections (like Lists, Sets, and other iterables). It is cleaner than a traditional for loop when you don’t need the index.
for-in with Lists
void main() {
List<String> fruits = ['Apple', 'Banana', 'Cherry', 'Date'];
// for-in -- clean and readable
for (String fruit in fruits) {
print(fruit);
}
// Output: Apple Banana Cherry Date
// Compare with traditional for loop
for (int i = 0; i < fruits.length; i++) {
print('${i + 1}. ${fruits[i]}');
}
// Output: 1. Apple 2. Banana 3. Cherry 4. Date
}
for-in with Numbers
void main() {
List<int> numbers = [10, 20, 30, 40, 50];
// Calculate the sum
int sum = 0;
for (int number in numbers) {
sum += number;
}
print('Sum: $sum'); // Sum: 150
// Find the maximum value
int max = numbers[0];
for (int number in numbers) {
if (number > max) {
max = number;
}
}
print('Max: $max'); // Max: 50
}
for-in when you just need each element. Use a traditional for loop when you need the index, or when you need to modify the list while iterating (which for-in does not allow).The forEach Method
Dart collections also have a forEach method that accepts a function. It does the same thing as for-in but uses a callback:
forEach Method
void main() {
List<String> colors = ['Red', 'Green', 'Blue'];
// Using forEach with an anonymous function
colors.forEach((color) {
print('Color: $color');
});
// Using forEach with arrow syntax (for single expressions)
colors.forEach((color) => print('I like $color'));
// With index using asMap()
colors.asMap().forEach((index, color) {
print('$index: $color');
});
// Output: 0: Red 1: Green 2: Blue
}
break and continue
Sometimes you need to alter the normal flow of a loop. break exits the loop entirely, while continue skips the rest of the current iteration and moves to the next one.
break -- Exit the Loop Early
void main() {
// Find the first number divisible by 7
for (int i = 1; i <= 100; i++) {
if (i % 7 == 0) {
print('First number divisible by 7: $i');
break; // Stop the loop immediately
}
}
// Output: First number divisible by 7: 7
// Search for an item in a list
List<String> names = ['Alice', 'Bob', 'Charlie', 'Diana'];
String searchFor = 'Charlie';
bool found = false;
for (String name in names) {
if (name == searchFor) {
found = true;
break; // No need to check remaining items
}
}
print('$searchFor found: $found'); // Charlie found: true
}
continue -- Skip to the Next Iteration
void main() {
// Print only odd numbers from 1 to 10
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
continue; // Skip even numbers
}
print(i);
}
// Output: 1 3 5 7 9
// Process only valid scores
List<int> scores = [85, -1, 92, 0, 78, -5, 95];
for (int score in scores) {
if (score <= 0) {
continue; // Skip invalid scores
}
print('Valid score: $score');
}
// Output: Valid score: 85 Valid score: 92 Valid score: 78 Valid score: 95
}
Nested Loops
You can place one loop inside another. The inner loop completes all its iterations for each single iteration of the outer loop.
Nested for Loops
void main() {
// Multiplication table (1-5)
for (int i = 1; i <= 5; i++) {
String row = '';
for (int j = 1; j <= 5; j++) {
row += '${(i * j).toString().padLeft(3)}';
}
print(row);
}
// Output:
// 1 2 3 4 5
// 2 4 6 8 10
// 3 6 9 12 15
// 4 8 12 16 20
// 5 10 15 20 25
}
Breaking Out of Nested Loops with Labels
void main() {
// Labels let you break out of a specific loop
outerLoop:
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
if (i + j == 6) {
print('Breaking at i=$i, j=$j');
break outerLoop; // Breaks the OUTER loop
}
}
}
// Output: Breaking at i=2, j=4
// Without the label, break would only exit the inner loop
}
Common Loop Patterns
Pattern: Accumulator (Sum, Count, Build String)
void main() {
List<double> prices = [9.99, 24.50, 3.75, 15.00, 42.99];
// Sum accumulator
double total = 0;
for (double price in prices) {
total += price;
}
print('Total: \$${total.toStringAsFixed(2)}'); // Total: $96.23
// Count accumulator
int expensiveCount = 0;
for (double price in prices) {
if (price > 20) {
expensiveCount++;
}
}
print('Expensive items: $expensiveCount'); // Expensive items: 2
// String builder
List<String> words = ['Dart', 'is', 'awesome'];
String sentence = '';
for (int i = 0; i < words.length; i++) {
sentence += words[i];
if (i < words.length - 1) sentence += ' ';
}
print(sentence); // Dart is awesome
}
Pattern: Search and Filter
void main() {
List<int> numbers = [12, 5, 8, 130, 44, 3, 99, 67];
// Find all numbers greater than 50
List<int> large = [];
for (int n in numbers) {
if (n > 50) {
large.add(n);
}
}
print('Numbers > 50: $large'); // Numbers > 50: [130, 99, 67]
// Find the first even number
for (int n in numbers) {
if (n % 2 == 0) {
print('First even: $n'); // First even: 12
break;
}
}
}
Choosing the Right Loop
•
for -- when you know the exact number of iterations or need an index.•
while -- when you loop until a condition changes (unknown iterations).•
do-while -- same as while, but the body must run at least once.•
for-in -- when iterating over a collection and you don’t need the index.•
forEach -- functional style, good for simple operations on each element.Practical Examples
Example: FizzBuzz
void main() {
// Classic programming challenge
for (int i = 1; i <= 20; i++) {
if (i % 3 == 0 && i % 5 == 0) {
print('FizzBuzz');
} else if (i % 3 == 0) {
print('Fizz');
} else if (i % 5 == 0) {
print('Buzz');
} else {
print(i);
}
}
}
Example: Simple Number Guessing Logic
void main() {
int secretNumber = 7;
List<int> guesses = [3, 9, 5, 7, 10];
int attempts = 0;
for (int guess in guesses) {
attempts++;
if (guess == secretNumber) {
print('Correct! Found $secretNumber in $attempts attempts.');
break;
} else if (guess < secretNumber) {
print('$guess is too low.');
} else {
print('$guess is too high.');
}
}
// Output:
// 3 is too low.
// 9 is too high.
// 5 is too low.
// Correct! Found 7 in 4 attempts.
}
Example: Reverse a String
void main() {
String original = 'Hello, Dart!';
String reversed = '';
for (int i = original.length - 1; i >= 0; i--) {
reversed += original[i];
}
print('Original: $original'); // Original: Hello, Dart!
print('Reversed: $reversed'); // Reversed: !traD ,olleH
}
Practice Exercise
Open DartPad and create a program that: (1) Uses a for loop to calculate the factorial of 10 (10! = 10 × 9 × 8 × ... × 1). (2) Uses a while loop to find the smallest power of 2 that is greater than 1000. (3) Uses for-in to iterate over a list of names and print only those with more than 4 characters. (4) Uses nested loops to print a right triangle of stars (5 rows). (5) Implements FizzBuzz from 1 to 30 using any loop type.