Если вам интересна производительность, я провел небольшой тест (используя мою библиотеку simple_benchmark
) для сравнения производительности решений и включил функцию из одного из моих пакетов:iteration_utilities.grouper
from iteration_utilities import grouper
import matplotlib as mpl
from simple_benchmark import BenchmarkBuilder
bench = BenchmarkBuilder()
@bench.add_function()
def Johnsyweb(l):
def pairwise(iterable):
"s -> (s0, s1), (s2, s3), (s4, s5), ..."
a = iter(iterable)
return zip(a, a)
for x, y in pairwise(l):
pass
@bench.add_function()
def Margus(data):
for i, k in zip(data[0::2], data[1::2]):
pass
@bench.add_function()
def pyanon(l):
list(zip(l,l[1:]))[::2]
@bench.add_function()
def taskinoor(l):
for i in range(0, len(l), 2):
l[i], l[i+1]
@bench.add_function()
def mic_e(it):
def pairwise(it):
it = iter(it)
while True:
try:
yield next(it), next(it)
except StopIteration:
return
for a, b in pairwise(it):
pass
@bench.add_function()
def MSeifert(it):
for item1, item2 in grouper(it, 2):
pass
bench.use_random_lists_as_arguments(sizes=[2**i for i in range(1, 20)])
benchmark_result = bench.run()
mpl.rcParams['figure.figsize'] = (8, 10)
benchmark_result.plot_both(relative_to=MSeifert)
Поэтому, если вы хотите самое быстрое решение без внешних зависимостей, вам, вероятно, следует просто использовать подходзадано Johnysweb (на момент написания статьи это наиболее одобренный и принятый ответ).
Если вы не возражаете против дополнительной зависимости, то grouper
из iteration_utilities
, вероятно, будет немного быстрее.
Дополнительные мысли
Некоторые подходы имеют некоторые ограничения, которые здесь не обсуждались.
Например, некоторые решения работают только для последовательностей (то есть списков, строки т. д.), например, решения Margus / pyanon / taskinoor, использующие индексирование, в то время как другие решения работают с любыми итерируемыми (то есть последовательностями и генераторами, итераторами), такими как Johnysweb / mic_e / mysolutions.
Затем Johnysweb также предоставил решение, которое работает для других размеров, отличных от 2, в то время как другие ответы - нет (хорошо, iteration_utilities.grouper
также позволяет установить количество элементов в «group»).
Тогда возникает также вопрос о том, что должно произойти, если в списке нечетное количество элементов.Оставшийся предмет должен быть уволен?Должен ли список быть дополнен, чтобы сделать его еще меньше?Оставшийся предмет должен быть возвращен как один?Другой ответ не касается этого вопроса напрямую, однако, если я ничего не пропустил, все они следуют подходу, согласно которому оставшийся элемент должен быть отклонен (за исключением ответа Taskinoors - который фактически вызовет исключение).
С помощью grouper
вы можете решить, что вы хотите сделать:
>>> from iteration_utilities import grouper
>>> list(grouper([1, 2, 3], 2)) # as single
[(1, 2), (3,)]
>>> list(grouper([1, 2, 3], 2, truncate=True)) # ignored
[(1, 2)]
>>> list(grouper([1, 2, 3], 2, fillvalue=None)) # padded
[(1, 2), (3, None)]