I like iterators!
def chunk(in_string,num_chunks):
chunk_size = len(in_string)//num_chunks
if len(in_string) % num_chunks: chunk_size += 1
iterator = iter(in_string)
for _ in range(num_chunks):
accumulator = list()
for _ in range(chunk_size):
try: accumulator.append(next(iterator))
except StopIteration: break
yield ''.join(accumulator)
## DEMO
>>> string = "a"*32+"b"*32+"c"*32+"d"*32
>>> list(chunk(string,4))
['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', 'cccccccccccccccccccccccccccccccc', 'ffffdffffdffffdffffdffffdffffdffffdffffdffffdffffffffd']
>>> string += "e" # so it's not evenly divisible
>>> list(chunk(string,4))
['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab', 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcc', 'ccccccccccccccccccccccccccccccffffd', 'ffffdffffdffffdffffdffffdffffdffffdffffdffffffffde']
Also demonstrably faster than textwrap.wrap
, although almost certainly less "good"
>>> timeit.timeit(lambda: list(chunk(string,4)),number=500)
0.047726927170444355
>>> timeit.timeit(lambda: textwrap.wrap(string,len(string)//4),number=500)
0.20812756575945457
And pretty easy to hack to work with any iterable (just drop the str.join
and yield accumulator unless isinstance(in_string,str)
)
# after a petty hack
>>> list(chunk([1,2,3,4,5,6,7,8,9,10,11,12],4))
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]