Learn
8.2.3.2 | NESTED LOOPS AND TWO-DIMENSIONAL ARRAYS
01 | EVERY TEST FOR EVERY STUDENT
Three students each complete four tests. A 2D array can store the twelve scores, but the program still needs a method for visiting them all.
Nested iteration means placing a loop inside another loop’s body. The body is the instruction or group of instructions repeated by a loop. One body execution is one iteration.
Let the outer loop select a student row. Inside it, let the inner loop visit every test column for that student. The inner loop finishes its four columns before the outer loop advances to the next row.
02 | CONNECT THE GRID TO ITS DECLARATION
Scores has three student rows and four test columns. The first index selects the student; the second selects the test. Every element holds INTEGER data.
The lower and upper bounds are inclusive. Three times four gives twelve stored elements. The declaration alone does not assign their values; the table shows a fully initialised example used later in this lesson.
DECLARE Scores : ARRAY[1:3, 1:4] OF INTEGER
| Student row | Test 1 | Test 2 | Test 3 | Test 4 |
|---|---|---|---|---|
| 1 | 8 | 6 | 7 | 5 |
| 2 | 4 | 10 | 9 | 6 |
| 3 | 7 | 5 | 8 | 10 |
03 | WRITE THE OUTER LOOP FIRST
Start with the larger repeated task: do something for each student. Student takes one, two and three in order. This loop executes its body three times.
A message inside this outer loop appears once per student. It does not automatically appear for every test because no test loop has yet been included.
Declare Student as INTEGER because it will be used as an array index.
DECLARE Student : INTEGER FOR Student ← 1 TO 3 OUTPUT "Processing student ", Student NEXT Student
04 | PLACE THE TEST LOOP INSIDE
Add an inner FOR controlled by Test. Each outer iteration reaches FOR Test ← 1 TO 4 again, so Test starts at one for the new student.
At Student one, the program reads [1,1], [1,2], [1,3] and [1,4]. Only then does Student become two for the next outer iteration. Test runs one to four again within row two.
Use separate counter variables. NEXT Test closes the inner loop before NEXT Student closes the outer loop.
DECLARE Student : INTEGER
DECLARE Test : INTEGER
FOR Student ← 1 TO 3
FOR Test ← 1 TO 4
OUTPUT Scores[Student, Test]
NEXT Test
NEXT Student05 | TRACE THE ORDER OF THE INDEX PAIRS
A traversal visits the elements in a planned order. This row-first traversal visits all columns of one row before moving down.
The table records the counters when the innermost OUTPUT executes. It does not claim a particular counter value after a FOR loop terminates.
| Visit | Student | Test | Element | Output |
|---|---|---|---|---|
| 1 | 1 | 1 | Scores[1,1] | 8 |
| 2 | 1 | 2 | Scores[1,2] | 6 |
| 3 | 1 | 3 | Scores[1,3] | 7 |
| 4 | 1 | 4 | Scores[1,4] | 5 |
| 5 | 2 | 1 | Scores[2,1] | 4 |
| 6 | 2 | 2 | Scores[2,2] | 10 |
| 7 | 2 | 3 | Scores[2,3] | 9 |
| 8 | 2 | 4 | Scores[2,4] | 6 |
| 9 | 3 | 1 | Scores[3,1] | 7 |
| 10 | 3 | 2 | Scores[3,2] | 5 |
| 11 | 3 | 3 | Scores[3,3] | 8 |
| 12 | 3 | 4 | Scores[3,4] | 10 |
06 | INITIALISE EVERY CELL WITH NESTED WRITES
Replace OUTPUT with an assignment to initialise each element. The same twelve index pairs now select destinations instead of sources.
After this loop every element is zero. Zero is supplied explicitly by the assignment. A declaration does not create that initial state by itself.
Keep the indices in the same order as their meanings. The bounds one-to-three and one-to-four belong to different dimensions.
FOR Student ← 1 TO 3
FOR Test ← 1 TO 4
Scores[Student, Test] ← 0
NEXT Test
NEXT Student07 | RECEIVE ONE INPUT PER CELL
INPUT Scores[Student, Test] receives a value for the current student’s current test. Including both counter values in the prompt helps the user place data correctly.
With no retries, the instruction executes twelve times: four inputs for each of three students. The first four inputs fill row one, the next four row two and the final four row three.
This example assumes every input is a valid INTEGER score. The prompt and array type do not enforce all application rules by themselves.
FOR Student ← 1 TO 3
FOR Test ← 1 TO 4
OUTPUT "Enter score for student ", Student, ", test ", Test
INPUT Scores[Student, Test]
NEXT Test
NEXT Student08 | EXPLORE THE NESTED TRAVERSAL
Choose a task and follow the grid one cell at a time. Fill begins with unassigned cells and writes the twelve example inputs. Read starts with all scores assigned. Row totals reads the scores into running totals without changing them.
| Student / test | 1 | 2 | 3 | 4 |
|---|
Each step represents one inner-body execution. In the totals task, the step also reports a row reset or completion when appropriate. The trace is an illustration of the pseudocode, not a general interpreter.
09 | A TOTAL FOR EACH ROW
A running total adds the values processed so far. StudentTotal must start at zero for each student, so initialise it inside the outer loop before the inner loop.
The inner loop adds all four scores for that student. After NEXT Test, the row total is ready and can be output once. Row one totals twenty-six, row two twenty-nine and row three thirty.
Resetting inside the inner loop would lose earlier test scores. Resetting only before the outer loop would carry earlier students’ scores into later row totals.
DECLARE StudentTotal : INTEGER
FOR Student ← 1 TO 3
StudentTotal ← 0
FOR Test ← 1 TO 4
StudentTotal ← StudentTotal + Scores[Student, Test]
NEXT Test
OUTPUT "Student ", Student, " total: ", StudentTotal
NEXT Student10 | RETAIN A GRAND TOTAL ACROSS ROWS
GrandTotal represents the whole activity, so initialise it once before the outer loop. After each row finishes, add StudentTotal once to GrandTotal.
The values become twenty-six, fifty-five and eighty-five. StudentTotal resets for each new row; GrandTotal retains the completed earlier rows.
Do not also add every score directly to GrandTotal if you are already adding its row total: that would count the same scores twice.
DECLARE GrandTotal : INTEGER
GrandTotal ← 0
FOR Student ← 1 TO 3
StudentTotal ← 0
FOR Test ← 1 TO 4
StudentTotal ← StudentTotal + Scores[Student, Test]
NEXT Test
OUTPUT StudentTotal
GrandTotal ← GrandTotal + StudentTotal
NEXT Student
OUTPUT "Grand total: ", GrandTotal| Completed row | StudentTotal | GrandTotal |
|---|---|---|
| 1 | 26 | 26 |
| 2 | 29 | 55 |
| 3 | 30 | 85 |
11 | PLACEMENT CHANGES EXECUTION COUNTS
In this three-by-four traversal, the outer body executes three times and the inner body twelve times. Instructions before the outer FOR or after NEXT Student execute once when the surrounding main program reaches them.
OUTPUT "Student complete" after NEXT Test but before NEXT Student appears three times. Inside the inner loop, an output appears twelve times unless selection skips it.
Count executions at the instruction’s actual level, not by multiplying every number you see. A conditional output can occur fewer times than the number of visited elements.
12 | VISIT COLUMNS FIRST WHEN THE JOB NEEDS IT
To display all students’ scores for test one before test two, use Test as the outer counter and Student as the inner counter.
The order becomes [1,1], [2,1], [3,1], then [1,2], [2,2], [3,2], and so on. The access remains Scores[Student, Test]: changing loop order does not change the declared meaning of the index positions.
This can support a total for each test column. Initialise a test total at the start of each outer Test iteration, then add the three student values within it.
FOR Test ← 1 TO 4
FOR Student ← 1 TO 3
OUTPUT Scores[Student, Test]
NEXT Student
NEXT Test13 | CHECK EVERY DIMENSION AND COUNTER
FOR Student ← 1 TO 4 would exceed the first dimension’s upper bound three. FOR Test ← 1 TO 3 would silently miss the fourth column. Swapping bounds is especially risky in a rectangular grid.
For an array declared [0:2, 0:3], use zero-to-two and zero-to-three instead. Three rows and four columns still make twelve elements, but valid indices differ.
Do not use Student as both active FOR counters. The inner loop would interfere with the outer loop’s control. Distinct names and aligned NEXT statements make the structure easier to check.
14 | RETRY THE CURRENT CELL BEFORE MOVING ON
To accept scores from zero to twenty, place a REPEAT validation loop inside the test loop. This is a third nested loop level: student, test and input retry.
Assume inputs are INTEGER. An invalid value is overwritten by another attempt at the same cell. Only a valid value lets execution leave REPEAT and advance Test.
The grid still receives twelve accepted scores, but it may require more than twelve input attempts. The first input twenty-five followed by eight adds an extra attempt for [1,1]; it does not advance directly to [1,2].
FOR Student ← 1 TO 3
FOR Test ← 1 TO 4
REPEAT
OUTPUT "Enter score from 0 to 20 for student ", Student, ", test ", Test
INPUT Scores[Student, Test]
UNTIL (Scores[Student, Test] >= 0) AND (Scores[Student, Test] <= 20)
NEXT Test
NEXT Student15 | EXPLAIN THE TWO LEVELS CLEARLY
A useful explanation is: “Student selects one row. For that row, Test visits columns one through four, therefore the inner body executes four times before the outer counter advances.”
Before writing, decide the intended traversal order, match each counter to its dimension, and identify which values reset per row or remain across the whole grid.
Check that all elements are assigned before reading, that the index order stays consistent and that totals are not counted twice. A small hand trace makes errors much easier to spot.
The next lesson explains why programs store data in files when it must be kept beyond a program run.