A collection's shape is part of its meaning. A three-dimensional array needs three index meanings; a record gives names to fields; a tuple groups a fixed sequence of values.
Content owner: Michael Print · Written for A-Level learners · Checked against official specifications
The idea to start with
An array uses indexes to access elements with a regular positional structure. A record groups named fields describing one entity; fields can have different types. A list represents an ordered collection, while a tuple represents a grouped sequence whose exact mutability depends on the language.
In Python a list is a resizable sequence and a tuple is immutable. A nested list can demonstrate indexed array operations, but it does not automatically enforce a homogeneous element type or fixed capacity. The second example imposes those array boundaries explicitly.
OCR H446 · 1.4.2(a,c), covering arrays up to three dimensions, records, lists and tuples. Python examples state where language behaviour differs from a fixed array.
Before you start
Useful foundations
Variables and loops
Zero-based indexing
Functions and boundary conditions
By the end, you should be able to
Select arrays, records, lists and tuples for stated data
Traverse every cell of a three-dimensional collection
Implement insertion and deletion in a fixed-capacity array
Check empty, full and out-of-range cases
Give each dimension a meaning
A 1D array can index scores by student. A 2D array adds assessment. A 3D collection can index readings by day, room and sample.
Write readings[day][room][sample] beside the design. Swapping coordinates can return a wrong cell without an exception if both indexes happen to be valid. Three dimensions describe coordinates, not three values inside each cell.
Give every index its own meaning
Day: first index→
Two days: valid zero-based indexes 0…1.
Room: second index→
Two rooms per day: indexes 0…1.
Sample: third index→
Three readings per room: indexes 0…2.
2×2×3=12 cells. For example, [1][0][2] selects day 1, room 0, sample 2.
Use records for fields and tuples for agreed positions
A learner record has name:string, score:integer and ready:Boolean. learner.score names the field clearly. Python dataclass attributes do not automatically validate every runtime assignment; validation remains separate.
A tuple uses agreed positions, such as (row, column). Python tuple positions cannot be reassigned. The colour example creates and traverses a tuple, then uses concatenation and slicing to build replacement tuples when adding or removing data.
The original tuple stays unchanged. Its immutability does not make contained objects immutable: it may contain a mutable list. Use a list or array for many changing records; one record describes one entity.
Traverse once, without sharing inner rows
Nested loops follow the documented dimensions. Values 100×day+10×room+sample expose coordinate-order mistakes: [1][0][2] prints 102 and all twelve cells sum to 672.
Each comprehension makes a fresh inner list. [[0]*3]*2 repeats references to one row instead; changing one apparent row can change another. Assign into one row and inspect a second to detect aliasing.
Traversal visits every cell once. Nested loops become quadratic only when their bounds grow together with the chosen input size; fixed dimensions do not establish that growth.
Python 3: independent rows, records and coordinatespython
from dataclasses import dataclass
readings = [
[[100 * day + 10 * room + sample for sample in range(3)]
for room in range(2)]
for day in range(2)
]
print(readings[1][0][2])
total = 0
for day in range(2):
for room in range(2):
for sample in range(3):
total += readings[day][room][sample]
print(total)
@dataclass
class Learner:
name: str
score: int
ready: bool
learners = [Learner('Mina', 8, True), Learner('Owen', 6, False)]
learners.append(Learner('Jia', 9, True))
for learner in learners:
print(learner.name, learner.score)
del learners[1]
position = (1, 2)
print(position[0], position[1])
colours = ('red', 'blue')
original = colours
colours = colours + ('green',)
colours = colours[:1] + colours[2:] # remove blue at index 1
for colour in colours:
print(colour)
print(original)
# Output:
# 102
# 672
# Mina 8
# Owen 6
# Jia 9
# 1 2
# red
# green
# ('red', 'blue')
A fixed array separates capacity from used length
Capacity is the maximum storage; used is the active length. In a capacity-four buffer, only indexes 0…used−1 belong to the logical sequence. Unused slots are outside it.
Insertion accepts positions 0…used, including the end. Deletion accepts only 0…used−1. Check these boundaries before moving data.
For deletion, save the removed value, shift subsequent values left, clear the old last slot and decrease used. The explicit loops expose the move direction.
Insert 8 into `[7,9]` at index 1
1
Check space and position
used=2, capacity=4; index 1 is a permitted insertion point.
2
Copy from the right
Copy 9 from index 1 to index 2, preserving it before overwriting its old slot.
3
Write the new value
Store 8 at index 1. Moving in the opposite direction could overwrite an uncopied value.
4
Update the length
Increase used to 3. The logical sequence is [7,8,9].
Worked example
Insert and remove within a capacity-four array
Begin empty. Insert 7 at zero, then 9 at the end: used=2 and the stored sequence is [7,9]. Inserting 8 at index one first copies 9 into index two, then writes 8, yielding [7,8,9].
Erase index zero: save 7, move 8 and 9 left, clear index two and set used=2. The logical sequence is [8,9] and the backing buffer is [8,9,None,None].
An empty deletion, an index equal to used for deletion, or an insertion index outside zero…used raises IndexError. Inserting when used equals capacity raises OverflowError. Those outcomes are part of the operation's contract, not values silently accepted by Python's negative-index rules.
Python 3: array operations with explicit length and capacitypython
def insert(buffer, used, index, value):
if not 0 <= index <= used:
raise IndexError('insertion index')
if used == len(buffer):
raise OverflowError('array full')
for position in range(used, index, -1):
buffer[position] = buffer[position - 1]
buffer[index] = value
return used + 1
def erase(buffer, used, index):
if not 0 <= index < used:
raise IndexError('deletion index')
removed = buffer[index]
for position in range(index, used - 1):
buffer[position] = buffer[position + 1]
buffer[used - 1] = None
return used - 1, removed
buffer = [None] * 4
used = 0
used = insert(buffer, used, 0, 7)
used = insert(buffer, used, used, 9)
used = insert(buffer, used, 1, 8)
print(buffer[:used])
used, removed = erase(buffer, used, 0)
print(removed, buffer[:used])
print(buffer)
# Output:
# [7, 8, 9]
# 7 [8, 9]
# [8, 9, None, None]
Original A-Level practice
6 original questions total 17 marks. Attempt each before opening the independently written indicative marking guidance.
Question 1
3 marks
For zero-based readings[day][room][sample] of dimensions 2×2×3, state the cell count and whether readings[1][1][3] is valid. [3 marks]
Show solution and marking guidance+
Indicative answer
There are 2×2×3=12 cells (1). The access is invalid (1), because the sample indexes are zero, one and two, so three is out of range (1).
Question 2
3 marks
Why is a record with name, score and ready fields suitable for one learner, while an array of such records is useful for a class? [3 marks]
Show solution and marking guidance+
Indicative answer
The record groups related fields describing one entity (1) and permits different field types with meaningful names (1). The array supplies indexed storage/traversal for many learner records (1).
Question 3
4 marks
A fixed array contains [4,8,12] with used=3 and capacity=5. Insert 6 at index one. State the two copies, final sequence and new used length. [4 marks]
Show solution and marking guidance+
Indicative answer
Copy index two's 12 to index three (1), then index one's 8 to index two (1). Write 6 at index one, giving [4,6,8,12] (1); used becomes four (1).
Question 4
2 marks
Why does [[0]*3]*2 fail when two independently mutable rows are required? [2 marks]
Show solution and marking guidance+
Indicative answer
The outer list stores two references to the same inner list (1). Updating a cell through one row therefore changes the row seen through the other reference (1).
Question 5
2 marks
Why should deleting index zero from an empty fixed-capacity sequence be rejected, and why should inserting into a full capacity-four buffer be rejected? [2 marks]
Show solution and marking guidance+
Indicative answer
No occupied index exists in the empty sequence (1), and the full buffer has no spare position (1). The Python implementation reports these conditions with IndexError and OverflowError respectively; naming those exceptions is not required for this question.
Question 6
3 marks
For the Python tuple (5,7,9), remove the middle value without mutating the original tuple, then append 11 to the replacement. Give both expressions and the final result. [3 marks]
Show solution and marking guidance+
Indicative answer
With values=(5,7,9), use replacement=values[:1]+values[2:], giving (5,9) (1). Use replacement=replacement+(11,) (1). The final tuple is (5,9,11); values remains (5,7,9) (1). Equivalent correctly constructed replacement tuples are acceptable.
Specification and references
This guide addresses OCR H446 1.4.2(a,c), covering arrays up to three dimensions, records, lists and tuples. Python examples state where language behaviour differs from a fixed array.. Check your examination year and the complete specification for the assessment scope.
These are independently written explanations and practice questions. CompSciTutoring.co.uk is not affiliated with or endorsed by an examination board. The marking guidance is indicative; always check the syllabus for your examination year.