Skip to content
myAudience.
← Explore the library

Lists, grids and records preserve different relationships

By UK GCSE Computer Science · independent study · myAudience

Two outer-list references point to one shared [8,0,0] row in the repeated-row construction. In the independently built construction, index0 points to [8,0,0] and index1 points to a separate [0,0,0]. Arrows represent references, not copied values.

Original built-in imagegen teaching raster; author inspected original and three served sizes2026-10-04. Independent derivative review pending. · Generated project artwork; no copied exam or publisher illustration. Independent rights/publication review pending.

Lists, grids and records preserve different relationships

A data structure organises related values so operations can use their relationships. A one-dimensional array has indexed elements; Python's list serves as an equivalent for these lessons, although it can change length and mix types unlike some arrays. An index selects a position, not a value to search for. For readings = [4,7,2], readings[1] is 7 because Python indexing starts at zero. Entry skills are finite loops and state tracing. A record groups named fields for one entity: a fictional item can have code, mass_g and fragile fields of different types. A list of records organises several entities without losing their field meanings.

A two-dimensional representation can use a list of row lists. grid[row][column] means select a row first and then a cell within it. Rows must be the same length if the contract says a rectangular grid. The expression [[0] * 3] * 2 repeats references to the same row, so changing one cell can change both apparent rows. Construct each row separately with a comprehension or a loop. This is an implementation aliasing issue, not a property of the abstract grid algorithm. Tests should change one cell and verify that a different row is unaffected.

For a fictional greenhouse, each row holds sensor readings. Row totals summarise each zone, while a column total summarises the same position across zones. Neither operation can be replaced by summing a flattened list if the zone distinction matters. The algorithm below validates rectangularity, then sums each row using a nested loop. It accepts an empty grid and returns an empty list, but rejects ragged rows. A grid with two empty rows is rectangular with zero columns and returns [0,0]; decide whether that is useful before integrating it into an application.

A record is often represented by a dictionary in Python, but dictionaries are not automatically checked record schemas. Accessing item["mass_g"] can fail if the key is absent. We use a fixed record shape in a small example and document it rather than implying any dictionary is safe. Local variables and fresh result lists help keep computation predictable. Copying a list of records shallowly does not copy each contained dictionary; updates may still be shared. This matters when a caller expects a report routine to leave its source data unchanged.

The reference diagram shows why repeating one row object differs from constructing two independent rows. Both left-hand references lead to the same changed row; the right-hand references lead to distinct rows, so changing row 0 leaves row 1 unchanged. This picture explains aliasing, not the row-sum invariant or a proof of rectangularity. To transfer the reasoning, write an invariant for both loop levels: while a row is processed, total equals its processed-cell sum; after k rows, result contains exactly the first k row totals. This combines local correctness with preservation of order. An attractive output list is not enough if a row was skipped or a shared row was accidentally mutated.

Runnable original Python 3 example (also saved verbatim in examples for CLI execution):
```python
def row_totals(grid):
"""Return row sums; reject ragged input; do not mutate rows."""
if not grid:
return []
width = len(grid[0])
if any(len(row) != width for row in grid):
raise ValueError("ragged grid")
result = []
for row in grid:
total = 0
for cell in row:
total += cell
result.append(total)
return result

def heavy_codes(items, limit_g):
return [item["code"] for item in items if item["mass_g"] >= limit_g]

assert row_totals([[2, 3], [4, 1]]) == [5, 5]
assert row_totals([[], []]) == [0, 0]
assert heavy_codes([{"code": "R1", "mass_g": 400, "fragile": True}], 400) == ["R1"]
rows = [[0 for _ in range(3)] for _ in range(2)]
rows[0][0] = 8
assert rows[1][0] == 0
```

Worked example: Find the row totals and column totals of [[2,3],[4,1]].

Rows sum to 2+3=5 and 4+1=5.

First column is 2+4=6; second is 3+1=4.

Both reports sum overall to 10, but that does not make their individual entries interchangeable.

Answer: Row totals [5,5]; column totals [6,4].

Check your understanding: Transfer: two records share the same code but have different masses. Should heavy_codes return one or two entries if both qualify? Define a revised contract for unique codes and a test that distinguishes it from the current function.

Answer: The current function returns two entries because it reports qualifying records in input order and does not require code uniqueness. A revised function could retain the first occurrence of each qualifying code; test two qualifying records with code R1 and expect ["R1"] rather than ["R1","R1"].

Why: Deduplication is a semantic decision, not a free optimisation. If codes identify physical parcels, duplicate records may be an error worth rejecting instead. State whether uniqueness applies to input records, output codes or both before changing the algorithm.

Author source references