Подтвердить что ты не робот

Питонический способ перебора последовательности, по 4 предмета за раз

Возможный дубликат:
Каков самый "питонический" способ перебора списка в кусках?

Я читаю некоторые PNG-данные, которые имеют 4 канала на пиксель. Я хотел бы перебирать данные по 1 пикселу за раз (что означает каждые 4 элемента = 1 пиксель, rgba).

red_channel = 0
while red_channel < len(raw_png_data):
    green_channel, blue_channel, alpha_channel = red_channel +1, red_channel +2, red_channel +3
    # do something with my 4 channels of pixel data ... raw_png_data[red_channel] etc
    red_channel += 4

Этот путь действительно не кажется "правильным". Есть ли более Pythonic путь для итерации по последовательности, по 4 элемента за раз, и эти 4 элемента распакованы?

4b9b3361

Ответ 1

(Python itertools должен действительно сделать все рецепты в качестве стандартных функций...)

Вы можете использовать функцию grouper:

from itertools import izip_longest
def grouper(n, iterable, fillvalue=None):
    "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)

Затем вы можете выполнять итерацию пикселей с помощью

for r,g,b,a in grouper(4, raw_png_data):
  ....

В качестве альтернативы вы можете использовать

irpd = iter(raw_png_data)
for r,g,b,a in zip(irpd, irpd, irpd, irpd):  # use itertools.izip in Python 2.x
  ....

Обратите внимание, что это приведет к измельчению последних нескольких байтов, если длина итерабельной длины не кратна 4. OTOH, функция grouper использует izip_longest, поэтому дополнительные байты будут дополнены None для этого.

Ответ 2

vars = [1, 2, 3, 4, 5, 6, 7, 8]
for a, b, c, d in zip(*[iter(vars)]*4):
    print a, b, c, d

Ответ 3

from itertools import izip
for r,g,b,a in izip(*[iter(data)]*4):
    ...

Ответ 4

for r, g, b, t in (data[i:i+4] for i in xrange(0, len(data)/4*4, 4)):
    print r, g, b, t

Ответ 5

Попробуйте что-то вроде этого:

for red, green, blue, alpha in raw_png_data:
    #do something

Вы можете вытащить несколько элементов и никогда не использовать итератор.:)

Изменить: это означало бы, что raw_png_data должен быть списком из 4 кортежей значений. Было бы очень pythonic поставить каждую группу rgba в кортеж, а затем добавить его в raw_png_data и прокрутить, как в моем примере.