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))
  1. values ← [10, 20, 30, 40, 50, 60, 70, 80]

    1values = [10, 20, 30, 40, 50, 60, 70, 80]2n = 3
    values this step[10, 20, 30, 40, 50, 60, 70, 80]values
  2. n ← 3

    1values = [10, 20, 30, 40, 50, 60, 70, 80]2n = 33first_n = []
    values this step3n
  3. first_n ← []

    2n = 33first_n = []4last_n = []
    values this step[]first_n
  4. last_n ← []

    3first_n = []4last_n = []5for i in range(n):
    values this step[]last_n
  5. i ← 0

    4last_n = []5for i in range(n):6    first_n.append(values[i])
    values this step0i
  6. first_n ← [10]

    5for i in range(n):6    first_n.append(values[i])7for i in range(n):
    values this step[] [10]first_n
  7. i ← 1

    4last_n = []5for i in range(n):6    first_n.append(values[i])
    values this step0 1i
  8. first_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_n
  9. i ← 2

    4last_n = []5for i in range(n):6    first_n.append(values[i])
    values this step1 2i
  10. first_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_n
  11. for i in range(n):

    4last_n = []5for i in range(n):6    first_n.append(values[i])
  12. 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 0i
  13. last_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_n
  14. i ← 1

    6    first_n.append(values[i])7for i in range(n):8    last_n.append(values[len(values) - n + i])
    values this step0 1i
  15. last_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_n
  16. i ← 2

    6    first_n.append(values[i])7for i in range(n):8    last_n.append(values[len(values) - n + i])
    values this step1 2i
  17. last_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_n
  18. for i in range(n):

    6    first_n.append(values[i])7for i in range(n):8    last_n.append(values[len(values) - n + i])
  19. 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_n and last_n grow visibly in the trace: [][10][10, 20][10, 20, 30] and [][60][60, 70][60, 70, 80].
  • values[-n:] is equivalent to values[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 to 0 at the start of the second loop, which is visible in the trace.