Return pieces of an iterable

0

Implement a generator function, chunker , which gets an iterable and returns a piece of specific size at a time. Using the function like this:

for chunk in chunker(range(25), 4):
    print(list(chunk))

should result in the output:

[0, 1, 2, 3]
[4, 5, 6, 7]
[8, 9, 10, 11]
[12, 13, 14, 15]
[16, 17, 18, 19]
[20, 21, 22, 23]
[24]

I'm having trouble once again on this subject about generators in Python. I can run the code, but not with the output I want. I am not able to create the columns as it asks in the question, I can only count the elements with range() .

This was my code:

def chunker(iterable, size):
    num = size
    for item in iterable:
       yield item,size


for chunk in chunker(range(25), 4):
    print(list(chunk))

That generated this output:

[0, 4]
[1, 4]
[2, 4]
[3, 4]
[4, 4]
[5, 4]
[6, 4]
[7, 4]
[8, 4]
[9, 4]
[10, 4]
[11, 4]
[12, 4]
[13, 4]
[14, 4]
[15, 4]
[16, 4]
[17, 4]
[18, 4]
[19, 4]
[20, 4]
[21, 4]
[22, 4]
[23, 4]
[24, 4]
    
asked by anonymous 19.04.2018 / 16:21

2 answers

2

Miguel's solution works, but it has limitations. The first is that it is necessary to convert the generator to list when passing as a parameter, which already hurts the requested in the statement, which specifies that the parameter is iterable (not just a list). Calling only chunker(range(25), 4) already produces the expected return, but it is a particularity of type range (it implements magic methods in order to generate some results without consuming the generator, such as __len__ ) . For other generators the solution might not work:

def gerador():
    nome = "Stack Overflow"
    for char in nome:
        yield char

def chunker(iterable, size):
    for i in range(0, len(iterable), size):
        yield iterable[i:i+size]

for chunk in chunker(gerador(), 4):
    print(list(chunk))

Resulting in:

Traceback (most recent call last):
  File "python", line 10, in <module>
  File "python", line 7, in chunker
TypeError: object of type 'generator' has no len()

The best solution would be to use the iter function in conjunction with the itertools.islice :

def chunker(iterable, size):
    it = iter(iterable)
    return iter(lambda: list(islice(it, size)), [])

See working at Repl.it | Ideone

So the output would be:

['S', 't', 'a', 'c']
['k', ' ', 'O', 'v']
['e', 'r', 'f', 'l']
['o', 'w']

Or, for the example of the question:

[0, 1, 2, 3]
[4, 5, 6, 7]
[8, 9, 10, 11]
[12, 13, 14, 15]
[16, 17, 18, 19]
[20, 21, 22, 23]
[24]
    
19.04.2018 / 18:13
2

You can do the following:

def chunker(iterable, size):
    for i in range(0, len(iterable), size): # percorremos o nosso range com um step de 4 neste caso, [0, 4, 8, 12, 16, 20, 24]
        yield iterable[i:i+size] # ficamos com os valores do nosso iteravel contidos no intervalo entre i e i+size, na primeira volta entre 0 e 0+4 ([0,1,2,3]) na segunda entre 4 e 4+4 ([4, 5, 6, 7]), etc...

c = chunker(list(range(25)), 4)
print(list(c)) # [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23], [24]]

You loop this generator like this:

for i in chunker(list(range(25)), 4):
    print(i)

STATEMENT

    
19.04.2018 / 17:37