Given a list:
import string
a = list(string.ascii_lowercase)
What is the Pythonic way to return every nth block of m elements? Note that this is different from just returning every nth element.
Desired result of taking every 1st of 3 blocks of 3 elements (take 3, skip 6, take 3, skip 6...):
['a', 'b', 'c', 'j', 'k', 'l', 's', 't', 'u']
I can get to this as:
import itertools
s1 = a[::9]
s2 = a[1::9]
s3 = a[2::9]
res = list(itertools.chain.from_iterable(zip(s1,s2, s3)))
Is there a cleaner way?
For a fixed order of select and skip, you can wrap indices taking the modulo on the total length of the window (9 here) and select only those beneath the given threshold, 3:
lst = [x for i, x in enumerate(a) if i % 9 < 3]
print(lst)
# ['a', 'b', 'c', 'j', 'k', 'l', 's', 't', 'u']
You can make this into a function that makes it more intuitive to use:
def select_skip(iterable, select, skip):
return [x for i, x in enumerate(iterable) if i % (select+skip) < select]
print(select_skip(a, select=3, skip=6))
# ['a', 'b', 'c', 'j', 'k', 'l', 's', 't', 'u']
Perhaps just writing a simple generator is the most readable
def thinger(iterable, take=3, skip=6):
it = iter(iterable)
try:
while True:
for i in range(take):
yield next(it)
for i in range(skip):
next(it)
except StopIteration:
return
This has the advantage of working even if the input is infinite, or not slicable (e.g. data coming in from a socket).
more_itertools
is a third-party library that implements itertools recipes and other helpful tools such as more_itertools.windowed
.
> pip install more_itertools
Code
import string
from more_itertools import windowed, flatten
m, n = 3, 6
list(flatten(windowed(string.ascii_lowercase, m, step=m+n)))
# ['a', 'b', 'c', 'j', 'k', 'l', 's', 't', 'u']
windowed
naturally steps one position per iteration. Given a new step by advancing beyond the overlaps (m
), the windows are appropriately determined.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With