Nesting one loop inside another lets your program work across rows and columns at the same time, and that is how you print multiplication tables, number grids, pyramids and checkerboards. The pattern is always the same: the outer loop chooses a row, the inner loop fills it.
How do you print a multiplication table?
A single loop is enough for one column of a table. The value you multiply by changes on every pass, so the loop counter does double duty as the multiplier.
public class MultiplicationTable {
public static void main(String[] args) {
int table = 7;
for (int i = 1; i <= 10; i++) {
System.out.println(table + " x " + i + " = " + (table * i));
}
}
}The output runs from one to ten:
7 x 1 = 7
7 x 2 = 14
7 x 3 = 21
7 x 4 = 28
7 x 5 = 35
7 x 6 = 42
7 x 7 = 49
7 x 8 = 56
7 x 9 = 63
7 x 10 = 70How do you build a grid of values?
Wrap that loop in another one and each pass of the outer loop becomes a row, with the inner loop producing the columns of that row.
public class ProductGrid {
public static void main(String[] args) {
int size = 4;
for (int row = 1; row <= size; row++) {
StringBuilder line = new StringBuilder();
for (int col = 1; col <= size; col++) {
line.append(String.format("%4d", row * col));
}
System.out.println(line);
}
}
}The output is a four by four grid of products, padded so the columns line up:
1 2 3 4
2 4 6 8
3 6 9 12
4 8 12 16Two details do the work here. The inner loop appends to a StringBuilder instead of printing, because printing inside the inner loop would break the line after every single value. And String.format("%4d", ...) pads each number to a fixed width, which is what keeps the columns vertical.
Notice how the outer loop variable is still readable inside the inner loop. That is the mechanism behind most grid patterns: the row index decides what the columns contain, so a cell can depend on both its row and its column. Whenever you are printing a shape, ask what each cell should look like in terms of its row and column number, and the two loops fall out of that answer.
How do you print a centred pyramid?
A pyramid needs three ingredients: some leading spaces to centre the row, then the characters themselves. The number of spaces shrinks as the row number grows, and the number of characters grows with it.
public class Pyramid {
public static void main(String[] args) {
int rows = 5;
for (int row = 1; row <= rows; row++) {
StringBuilder line = new StringBuilder();
for (int space = 0; space < rows - row; space++) {
line.append(' ');
}
for (int star = 0; star < 2 * row - 1; star++) {
line.append('*');
}
System.out.println(line);
}
}
}The output is a centred pyramid:
*
***
*****
*******
*********Notice the shape of the formulas: rows - row spaces and 2 * row - 1 characters. Deriving the two numbers first and then writing the loops is much easier than fiddling with the output until it looks right.
How does a checkerboard pattern work?
A checkerboard is a grid where the character depends on the sum of the row and column indexes. When that sum is even you get one character, and when it is odd you get the other.
public class Checkerboard {
public static void main(String[] args) {
int size = 6;
for (int row = 0; row < size; row++) {
StringBuilder line = new StringBuilder();
for (int col = 0; col < size; col++) {
line.append((row + col) % 2 == 0 ? "X " : "o ");
}
System.out.println(line);
}
}
}The output alternates on every row:
X o X o X o
o X o X o X
X o X o X o
o X o X o X
X o X o X o
o X o X o XThe parity of row + col is what flips the character, and because each row starts on the opposite parity to the one above, the pattern alternates automatically. The same trick draws a chess board or any two-colour grid.
What goes wrong when you nest loops?
Nested loops multiply their work. Two loops that each run a hundred times run the inner body ten thousand times, and three levels of nesting turn that into a million. Before you write a third level, check whether a flat loop with an index would do the same work more cheaply.
public class GridStatistics {
public static void main(String[] args) {
int size = 5;
int sum = 0;
for (int row = 1; row <= size; row++) {
for (int col = 1; col <= size; col++) {
sum += row * col;
}
}
System.out.println("cells: " + (size * size));
System.out.println("sum of products: " + sum);
}
}The output confirms the cell count and the total:
cells: 25
sum of products: 225The inner body ran 25 times because the outer loop ran 5 times and the inner loop ran 5 times each. The same idea matters when you break out of nested loops: a plain break only ends the inner loop, so the outer loop keeps starting new rows. Use a label when you mean to leave both.
There is a second trap in nested loops that has nothing to do with performance: the same variable name used for both counters. If you write int i in the outer loop and int i in the inner one, the compiler rejects it, because the inner declaration would hide the outer one and the outer loop could no longer advance. Use different names, or declare the counters in the for headers where each has its own scope.
Summary
- The outer loop picks the row and the inner loop fills it, so build the row into a string and print it once the inner loop finishes.
- Use
String.formatwith a width to line columns up vertically. - Work out the formula for each part of the pattern first, such as
rows - rowspaces or2 * row - 1characters. - Patterns that alternate rely on the parity of the row plus column indexes.
- Nested loops multiply the work, so a third level of nesting deserves a second look.
- A break inside the inner loop leaves only that loop; label the outer one when you need to leave both.
Try it yourself: print a right-aligned triangle of stars with five rows, then the same triangle pointing left, then a diamond made of four nested shapes one after the other. Underneath each one, print the number of characters you actually output so you can check the shape is what you intended. Finally, change your inner loop to stop at row instead of size and describe in one sentence how the output changes and why the total number of characters shrinks.