Lists and Records
Slice Select
Extract the first N and last N elements of a list by building two new lists with index loops. The trace shows each append growing the output lists one element at a time, making the index arithmetic visible.
By hand
Two separate loops, each running n times. The first loop picks values[i]
directly. The second computes the start offset as len(values) - n and adds
i to step forward from there.
naive.py
Replay: real traced execution (multi-file project)
values = [10, 20, 30, 40, 50, 60, 70, 80]
n = 3
first_n = []
last_n = []
for i in range(n):
first_n.append(values[i])
for i in range(n):
last_n.append(values[len(values) - n + i])
print('RESULT:', (first_n, last_n))
values ← [10, 20, 30, 40, 50, 60, 70, 80]
1values = [10, 20, 30, 40, 50, 60, 70, 80]2n = 3values this step[10, 20, 30, 40, 50, 60, 70, 80]valuesn ← 3
1values = [10, 20, 30, 40, 50, 60, 70, 80]2n = 33first_n = []values this step3nfirst_n ← []
2n = 33first_n = []4last_n = []values this step[]first_nlast_n ← []
3first_n = []4last_n = []5for i in range(n):values this step[]last_ni ← 0
4last_n = []5for i in range(n):6 first_n.append(values[i])values this step0ifirst_n ← [10]
5for i in range(n):6 first_n.append(values[i])7for i in range(n):values this step[] → [10]first_ni ← 1
4last_n = []5for i in range(n):6 first_n.append(values[i])values this step0 → 1ifirst_n ← [10, 20]
5for i in range(n):6 first_n.append(values[i])7for i in range(n):values this step[10] → [10, 20]first_ni ← 2
4last_n = []5for i in range(n):6 first_n.append(values[i])values this step1 → 2ifirst_n ← [10, 20, 30]
5for i in range(n):6 first_n.append(values[i])7for i in range(n):values this step[10, 20] → [10, 20, 30]first_nfor i in range(n):
4last_n = []5for i in range(n):6 first_n.append(values[i])i ← 0
6 first_n.append(values[i])7for i in range(n):8 last_n.append(values[len(values) - n + i])values this step2 → 0ilast_n ← [60]
7for i in range(n):8 last_n.append(values[len(values) - n + i])9print('RESULT:', (first_n, last_n))values this step[] → [60]last_ni ← 1
6 first_n.append(values[i])7for i in range(n):8 last_n.append(values[len(values) - n + i])values this step0 → 1ilast_n ← [60, 70]
7for i in range(n):8 last_n.append(values[len(values) - n + i])9print('RESULT:', (first_n, last_n))values this step[60] → [60, 70]last_ni ← 2
6 first_n.append(values[i])7for i in range(n):8 last_n.append(values[len(values) - n + i])values this step1 → 2ilast_n ← [60, 70, 80]
7for i in range(n):8 last_n.append(values[len(values) - n + i])9print('RESULT:', (first_n, last_n))values this step[60, 70] → [60, 70, 80]last_nfor i in range(n):
6 first_n.append(values[i])7for i in range(n):8 last_n.append(values[len(values) - n + i])stdout ← RESULT: ([10, 20, 30], [60, 70, 80])
8 last_n.append(values[len(values) - n + i])9print('RESULT:', (first_n, last_n))values this stepRESULT: ([10, 20, 30], [60, 70, 80])stdout
The Pythonic way
Slice syntax values[:n] and values[-n:] express the same selections in
one token each. Negative indices count from the end, so no length arithmetic
is needed.
library.py
values = [10, 20, 30, 40, 50, 60, 70, 80]
n = 3
first_n = values[:n]
last_n = values[-n:]
print('RESULT:', (first_n, last_n))
RESULT: ([10, 20, 30], [60, 70, 80])
Implementation notes
first_nandlast_ngrow visibly in the trace:[]→[10]→[10, 20]→[10, 20, 30]and[]→[60]→[60, 70]→[60, 70, 80].values[-n:]is equivalent tovalues[len(values)-n:]; Python resolves the negative index internally, which is exactly what the naive loop computes by hand.- The two loops share the variable
i; its value resets to0at the start of the second loop, which is visible in the trace.