Ответы:
Вам нужна pairwise()
(или grouped()
) реализация.
Для Python 2:
from itertools import izip
def pairwise(iterable):
"s -> (s0, s1), (s2, s3), (s4, s5), ..."
a = iter(iterable)
return izip(a, a)
for x, y in pairwise(l):
print "%d + %d = %d" % (x, y, x + y)
Или, в более общем плане:
from itertools import izip
def grouped(iterable, n):
"s -> (s0,s1,s2,...sn-1), (sn,sn+1,sn+2,...s2n-1), (s2n,s2n+1,s2n+2,...s3n-1), ..."
return izip(*[iter(iterable)]*n)
for x, y in grouped(l, 2):
print "%d + %d = %d" % (x, y, x + y)
В Python 3 вы можете заменить izip
встроенной zip()
функцией и удалить import
.
Все кредит Мартино за его ответ на мой вопрос , я нашел , что это будет очень эффективным , поскольку он лишь перебирает один раз по списку и не создает какие - либо ненужные списки в этом процессе.
NB : Это не следует путать с pairwise
рецептом в собственной itertools
документации Python , который дает s -> (s0, s1), (s1, s2), (s2, s3), ...
, как указал @lazyr в комментариях.
Небольшое дополнение для тех, кто хотел бы выполнить проверку типов с помощью Mypy на Python 3:
from typing import Iterable, Tuple, TypeVar
T = TypeVar("T")
def grouped(iterable: Iterable[T], n=2) -> Iterable[Tuple[T, ...]]:
"""s -> (s0,s1,s2,...sn-1), (sn,sn+1,sn+2,...s2n-1), ..."""
return zip(*[iter(iterable)] * n)
s -> (s0,s1), (s1,s2), (s2, s3), ...
itertools
функцией рецепта с тем же именем. Конечно, ваш быстрее ...
izip_longest()
вместо izip()
. Например: list(izip_longest(*[iter([1, 2, 3])]*2, fillvalue=0))
-> [(1, 2), (3, 0)]
. Надеюсь это поможет.
Ну, вам нужен кортеж из 2 элементов, так
data = [1,2,3,4,5,6]
for i,k in zip(data[0::2], data[1::2]):
print str(i), '+', str(k), '=', str(i+k)
Куда:
data[0::2]
означает создать подмножество элементов, которые (index % 2 == 0)
zip(x,y)
создает коллекцию кортежей из коллекций x и y с одинаковыми индексными элементами.for i, j, k in zip(data[0::3], data[1::3], data[2::3]):
import
не один из них.
>>> l = [1,2,3,4,5,6]
>>> zip(l,l[1:])
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]
>>> zip(l,l[1:])[::2]
[(1, 2), (3, 4), (5, 6)]
>>> [a+b for a,b in zip(l,l[1:])[::2]]
[3, 7, 11]
>>> ["%d + %d = %d" % (a,b,a+b) for a,b in zip(l,l[1:])[::2]]
['1 + 2 = 3', '3 + 4 = 7', '5 + 6 = 11']
zip
возвращает zip
объект в Python 3, который не является подписным. Сначала его нужно преобразовать в последовательность ( list
, tuple
и т. Д.), Но «не работает» немного растянуто.
Простое решение
l = [1, 2, 3, 4, 5, 6] для i в диапазоне (0, len (l), 2): print str (l [i]), '+', str (l [i + 1]), '=', str (l [i] + l [i + 1])
((l[i], l[i+1])for i in range(0, len(l), 2))
для генератора, может быть легко модифицирован для более длинных кортежей.
Несмотря на то, что все ответы zip
верны, я считаю, что реализация этой функциональности самостоятельно приводит к более читабельному коду:
def pairwise(it):
it = iter(it)
while True:
try:
yield next(it), next(it)
except StopIteration:
# no more elements in the iterator
return
Эта it = iter(it)
часть гарантирует, что it
это итератор, а не итерация. Если it
уже есть итератор, эта строка не используется.
Использование:
for a, b in pairwise([0, 1, 2, 3, 4, 5]):
print(a + b)
it
является только итератором, а не итерацией. Другие решения, похоже, полагаются на возможность создания двух независимых итераторов для последовательности.
Я надеюсь, что это будет еще более элегантный способ сделать это.
a = [1,2,3,4,5,6]
zip(a[::2], a[1::2])
[(1, 2), (3, 4), (5, 6)]
Если вам интересна производительность, я провел небольшой тест (используя свою библиотеку 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 / мои решения.
Затем Johnysweb также предоставил решение, которое работает для других размеров, отличных от 2, в то время как другие ответы - нет (хорошо, iteration_utilities.grouper
также позволяет установить количество элементов в «группу»).
Тогда возникает также вопрос о том, что должно произойти, если в списке присутствует нечетное количество элементов. Оставшийся предмет должен быть уволен? Должен ли список быть дополнен, чтобы сделать его равным по размеру? Оставшийся предмет должен быть возвращен как один? Другой ответ не касается этого вопроса напрямую, однако, если я ничего не пропустил, все они следуют подходу, согласно которому оставшийся элемент должен быть отклонен (за исключением ответа 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)]
Используйте zip
и iter
команды вместе:
Я считаю это решение iter
довольно элегантным:
it = iter(l)
list(zip(it, it))
# [(1, 2), (3, 4), (5, 6)]
Который я нашел в документации по Python 3 zip .
it = iter(l)
print(*(f'{u} + {v} = {u+v}' for u, v in zip(it, it)), sep='\n')
# 1 + 2 = 3
# 3 + 4 = 7
# 5 + 6 = 11
Чтобы обобщить N
элементы за раз:
N = 2
list(zip(*([iter(l)] * N)))
# [(1, 2), (3, 4), (5, 6)]
for (i, k) in zip(l[::2], l[1::2]):
print i, "+", k, "=", i+k
zip(*iterable)
возвращает кортеж со следующим элементом каждой итерации.
l[::2]
возвращает 1-й, 3-й, 5-й и т. д. элемент списка: первое двоеточие указывает, что срез начинается с начала, потому что за ним нет номера, второе двоеточие необходимо только в том случае, если вы хотите шаг в срезе '(в данном случае 2).
l[1::2]
делает то же самое, но начинается со второго элемента списков, поэтому возвращает 2-й, 4-й, 6-й и т. д. элемент исходного списка.
[number::number]
работает синтаксис. полезно для тех, кто не часто использует python
Вы можете использовать пакет more_itertools .
import more_itertools
lst = range(1, 7)
for i, j in more_itertools.chunked(lst, 2):
print(f'{i} + {j} = {i+j}')
С распаковкой:
l = [1,2,3,4,5,6]
while l:
i, k, *l = l
print(str(i), '+', str(k), '=', str(i+k))
Для всех, кто может помочь, вот решение подобной проблемы, но с перекрывающимися парами (вместо взаимоисключающих пар).
Из документации по Python itertools :
from itertools import izip
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return izip(a, b)
Или, в более общем плане:
from itertools import izip
def groupwise(iterable, n=2):
"s -> (s0,s1,...,sn-1), (s1,s2,...,sn), (s2,s3,...,sn+1), ..."
t = tee(iterable, n)
for i in range(1, n):
for j in range(0, i):
next(t[i], None)
return izip(*t)
Мне нужно разделить список на число и исправить это следующим образом.
l = [1,2,3,4,5,6]
def divideByN(data, n):
return [data[i*n : (i+1)*n] for i in range(len(data)//n)]
>>> print(divideByN(l,2))
[[1, 2], [3, 4], [5, 6]]
>>> print(divideByN(l,3))
[[1, 2, 3], [4, 5, 6]]
Есть много способов сделать это. Например:
lst = [1,2,3,4,5,6]
[(lst[i], lst[i+1]) for i,_ in enumerate(lst[:-1])]
>>>[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]
[i for i in zip(*[iter(lst)]*2)]
>>>[(1, 2), (3, 4), (5, 6)]
Я подумал, что это хорошее место, чтобы поделиться моим обобщением этого для n> 2, которое является просто скользящим окном над повторяемым:
def sliding_window(iterable, n):
its = [ itertools.islice(iter, i, None)
for i, iter
in enumerate(itertools.tee(iterable, n)) ]
return itertools.izip(*its)
Используя набор текста, вы можете проверить данные, используя инструмент статического анализа mypy :
from typing import Iterator, Any, Iterable, TypeVar, Tuple
T_ = TypeVar('T_')
Pairs_Iter = Iterator[Tuple[T_, T_]]
def legs(iterable: Iterator[T_]) -> Pairs_Iter:
begin = next(iterable)
for end in iterable:
yield begin, end
begin = end
Упрощенный подход:
[(a[i],a[i+1]) for i in range(0,len(a),2)]
это полезно, если ваш массив - это, и вы хотите итерировать его по парам. Чтобы выполнить итерации по триплетам или более, просто измените команду шага «range», например:
[(a[i],a[i+1],a[i+2]) for i in range(0,len(a),3)]
(вам придется иметь дело с лишними значениями, если длина вашего массива и шаг не подходят)
from itertools import tee
def pairwise(iterable):
a = iter(iterable)
for i in a:
try:
yield (i, next(a))
except StopIteration:
yield(i, None)
for i in pairwise([3, 7, 8, 9, 90, 900]):
print(i)
Вывод:
(3, 7)
(8, 9)
(90, 900)
>
Здесь у нас может быть alt_elem
метод, который может вписаться в ваш цикл for.
def alt_elem(list, index=2):
for i, elem in enumerate(list, start=1):
if not i % index:
yield tuple(list[i-index:i])
a = range(10)
for index in [2, 3, 4]:
print("With index: {0}".format(index))
for i in alt_elem(a, index):
print(i)
Вывод:
With index: 2
(0, 1)
(2, 3)
(4, 5)
(6, 7)
(8, 9)
With index: 3
(0, 1, 2)
(3, 4, 5)
(6, 7, 8)
With index: 4
(0, 1, 2, 3)
(4, 5, 6, 7)
Примечание. Приведенное выше решение может быть неэффективным, учитывая операции, выполняемые в func.