If you do not want to spend additional memory on the smaller lists, you have two possibilities:
Either you can destroy/reduce the original list as you create the smaller lists. You could use collections.deque
, providing O(1) removal and insertion at both ends:
>>> from collections import deque
>>> deq = deque(range(20))
>>> front = deque(deq.popleft() for _ in range(10))
>>> front
deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> deq # original list reduced, can be used as 2nd list
deque([10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
Or you can create two views on parts of the smaller lists, meaning that the original list would be altered if the smaller lists are modified, and vice versa. For instance, use numpy.array
for your numbers and create slices (being views) on that array:
>>> import numpy as np
>>> arr = np.array(range(20))
>>> front = arr[:10]
>>> back = arr[10:]
>>> front[3] = 100
>>> arr # original list modified
array([ 0, 1, 2, 100, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19])
If you have to use plain Python list
, you could also use list.pop
. However, as explained in the documentation for deque
, you should not use pop(0)
, as this will have to re-organize the entire list each time you pop an element, giving you O(n²) for extracting half of the list. Instead, use pop()
to pop from the end of the list. To restore the original order, you could first pop into a temporary list, and then pop from that list, reversing it twice.
>>> lst = list(range(10))
>>> tmp = [lst.pop() for _ in range(5)]
>>> front, back = lst, [tmp.pop() for _ in range(len(tmp))]
>>> front, back
([0, 1, 2, 3, 4], [5, 6, 7, 8, 9])