>>> theList = list(range(10))
>>> N = 3
>>> subList = [theList[n:n+N] for n in range(0, len(theList), N)]
>>> subList
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
How would I do this without list slicing?
>>> theList = list(range(10))
>>> N = 3
>>> subList = [theList[n:n+N] for n in range(0, len(theList), N)]
>>> subList
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
How would I do this without list slicing?
Use the modulus operator %
.
def split_by_n(n, lst):
final = []
sublist = []
for i in range(0, len(lst)):
if i % n != 0: # if i/n has no remainders
sublist.append(lst[i])
elif i != 0: # Reached the end of a sublist. Append to parent and reset.
final.append(sublist)
sublist = []
sublist.append(lst[i])
else: # 0 mod n is 0, so just make sure to add it anyways
sublist.append(lst[i])
final.append(sublist)
return final
There are several methods:
You could use nested list comprehension with indexes into the list:
(extensive use of indexes is as unPythonic as it gets though)
theList = list(range(10))
N = 3
L = len(theList)
subList = [ [theList[j] for j in range(i,min(i+N,L))] for i in range(0,L,N) ]
print(subList)
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
You could also do it with itertools.groupby using an iterator for the grouping key, or itertools.islice( ,N) for each subranges:
from itertools import groupby
group = iter(range(len(theList)))
subList = [ list(g) for _,g in groupby(theList,key=lambda _:next(group)//N) ]
print(subList)
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
from itertools import islice
iList = iter(theList)
subList = [ list(islice(iList,N)) for _ in range(0,len(theList),N) ]
print(subList)
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
If you can't use libraries, you could use zip() to get chunks of the iterator in the list comprehension:
iList = iter(theList)
subList = [[n for _,n in zip(range(N),iList)] for _ in range(0,len(theList),N)]
print(subList)
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
Or map with the next() function:
iList = iter(theList)
subList = [ [f, *map(next,[iList]*(N-1))] for f in iList ]
print(subList)
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
Of course, there's always the good old for-loop method:
subList = [[]]
for n in theList:
L,V = (subList[-1],n) if len(subList[-1])<N else (subList,[n])
L.append(V)
print(subList)
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
Here's a (possibly over-kill) solution using itertools:
Step 1. convert theList
into a generator:
gList = (x for x in theList)
Step 2. itertools.islice
yields groups of N (forever):
import itertools as it
z1 = list(it.islice(gList,N)) # [0,1,2]
z2 = list(it.islice(gList,N)) # [3,4,5]
z3 = list(it.islice(gList,N)) # [6,7,8]
z4 = list(it.islice(gList,N)) # [9]
z5 = list(it.islice(gList,N)) # [], etc.
(Note we need to reset gList
after this.)
Step 3. Wrap this up in another generator and use itertools.takewhile
:
import itertools as it
gList = (x for x in theList)
subList = list(it.takewhile(lambda y: len(y) > 0,
(list(it.islice(gList,N)) for _ in it.count(1))))
here it.count(1)
is acting like a while True:
loop