How do I make a for loop or a list comprehension so that every iteration gives me two elements?
l = [1,2,3,4,5,6]
for i,k in ???:
print str(i), '+', str(k), '=', str(i+k)
Output:
1+2=3
3+4=7
5+6=11
回答 0
您需要一个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)
You need a pairwise() (or grouped()) implementation.
For 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)
Or, more generally:
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)
In Python 3, you can replace izip with the built-in zip() function, and drop the import.
All credit to martineau for his answer to my question, I have found this to be very efficient as it only iterates once over the list and does not create any unnecessary lists in the process.
N.B: This should not be confused with the pairwise recipe in Python’s own itertools documentation, which yields s -> (s0, s1), (s1, s2), (s2, s3), ..., as pointed out by @lazyr in the comments.
Little addition for those who would like to do type checking with mypy on Python 3:
from iteration_utilities import grouper
import matplotlib as mpl
from simple_benchmark importBenchmarkBuilder
bench =BenchmarkBuilder()@bench.add_function()defJohnsyweb(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()defMargus(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)whileTrue:try:yield next(it), next(it)exceptStopIteration:returnfor a, b in pairwise(it):pass@bench.add_function()defMSeifert(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)
In case you’re interested in the performance, I did a small benchmark (using my library simple_benchmark) to compare the performance of the solutions and I included a function from one of my packages: 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)
So if you want the fastest solution without external dependencies you probably should just use the approach given by Johnysweb (at the time of writing it’s the most upvoted and accepted answer).
If you don’t mind the additional dependency then the grouper from iteration_utilities will probably be a bit faster.
Additional thoughts
Some of the approaches have some restrictions, that haven’t been discussed here.
For example a few solutions only work for sequences (that is lists, strings, etc.), for example Margus/pyanon/taskinoor solutions which uses indexing while other solutions work on any iterable (that is sequences and generators, iterators) like Johnysweb/mic_e/my solutions.
Then Johnysweb also provided a solution that works for other sizes than 2 while the other answers don’t (okay, the iteration_utilities.grouper also allows setting the number of elements to “group”).
Then there is also the question about what should happen if there is an odd number of elements in the list. Should the remaining item be dismissed? Should the list be padded to make it even sized? Should the remaining item be returned as single? The other answer don’t address this point directly, however if I haven’t overlooked anything they all follow the approach that the remaining item should be dismissed (except for taskinoors answer – that will actually raise an Exception).
for (i, k) in zip(l[::2], l[1::2]):
print i, "+", k, "=", i+k
zip(*iterable) returns a tuple with the next element of each iterable.
l[::2] returns the 1st, the 3rd, the 5th, etc. element of the list: the first colon indicates that the slice starts at the beginning because there’s no number behind it, the second colon is only needed if you want a ‘step in the slice’ (in this case 2).
l[1::2] does the same thing but starts in the second element of the lists so it returns the 2nd, the 4th, 6th, etc. element of the original list.
回答 9
带包装:
l =[1,2,3,4,5,6]while l:
i, k,*l = l
print(str(i),'+', str(k),'=', str(i+k))
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)
Or, more generally:
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)
import more_itertools
lst = range(1, 7)
for i, j in more_itertools.chunked(lst, 2):
print(f'{i} + {j} = {i+j}')
回答 12
我需要将列表除以数字并固定不变。
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]]
I need to divide a list by a number and fixed like this.
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]]
回答 13
有很多方法可以做到这一点。例如:
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)]
Thought that this is a good place to share my generalization of this for n>2, which is just a sliding window over an iterable:
def sliding_window(iterable, n):
its = [ itertools.islice(iter, i, None)
for i, iter
in enumerate(itertools.tee(iterable, n)) ]
return itertools.izip(*its)
回答 15
这个问题的标题具有误导性,您似乎正在寻找连续对,但如果要遍历所有可能对的集合,则可以使用以下方法:
for i,v in enumerate(items[:-1]):for u in items[i+1:]:
The title of this question is misleading, you seem to be looking for consecutive pairs, but if you want to iterate over the set of all possible pairs than this will work :
for i,v in enumerate(items[:-1]):
for u in items[i+1:]:
from typing importIterator,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
Using typing so you can verify data using mypy static analysis tool:
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
this is useful if your array is a and you want to iterate on it by pairs.
To iterate on triplets or more just change the “range” step command, for example:
[(a[i],a[i+1],a[i+2]) for i in range(0,len(a),3)]
(you have to deal with excess values if your array length and the step do not fit)
回答 18
在这里,我们可以找到alt_elem适合您的for循环的方法。
def alt_elem(list, index=2):for i, elem in enumerate(list, start=1):ifnot 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)
Here we can have alt_elem method which can fit in your for loop.
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)