В Python легко разбить длинный список n на куски k , если n кратен k (IOW, n % k == 0
). Вот мой любимый подход (прямо из документов ):
>>> k = 3
>>> n = 5 * k
>>> x = range(k * 5)
>>> zip(*[iter(x)] * k)
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, 14)]
(Хитрость заключается в том, что [iter(x)] * k
создает список k ссылок на того же итератора , возвращаемый iter(x)
. Затем zip
генерирует каждый кусок путем вызова каждая из k копий итератора ровно один раз. *
перед [iter(x)] * k
необходимо, потому что zip
ожидает получить свои аргументы как "отдельные" итераторы, а не их список.)
Главный недостаток, который я вижу в этой идиоме, состоит в том, что, когда n не кратно k (IOW, n % k > 0
), оставленные записи просто пропускаются ; e.g.:
>>> zip(*[iter(x)] * (k + 1))
[(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11)]
Существует альтернативная идиома, которая немного длиннее для ввода, дает тот же результат, что и выше, когда n % k == 0
, и имеет более приемлемое поведение, когда n % k > 0
:
>>> map(None, *[iter(x)] * k)
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, 14)]
>>> map(None, *[iter(x)] * (k + 1))
[(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11), (12, 13, 14, None)]
По крайней мере, здесь оставленные записи сохраняются, но последний кусок дополняется None
. Если кто-то просто хочет другое значение для заполнения, то itertools.izip_longest
решит проблему.
Но предположим, что желаемое решение - это то, в котором последний кусок остается незаполненным, т.е.
[(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11), (12, 13, 14)]
Есть ли простой способ изменить идиому map(None, *[iter(x)]*k)
для получения этого результата?
(Конечно, решить эту проблему несложно, написав функцию (см., Например, множество прекрасных ответов на Как разбить список на куски одинакового размера? или Какой самый «питонный» способ перебрать список по частям? ). Поэтому более точный заголовок для этого вопроса будет «Как спасти идиому map(None, *[iter(x)]*k)
?», Но я думаю, что это сбило бы с толку много читателей.)
Я был поражен тем, насколько легко разбить список на куски одинакового размера, и насколько трудно ( в сравнении! ) избавиться от нежелательных отступов, даже несмотря на две проблемы кажется, сравнимой сложности.