Reputation: 17928
I have defined a generator that yields log entries from Elasticsearch:
def gen():
....
for hit in results:
yield hit
How can I loop through two elements at the same time? Something in the lines of:
for one, two in gen():
...
By two elements I mean this: A, B
, B, C
, ..., Y, Z
(for a generated list of A, B, ..., Y, Z
).
Upvotes: 7
Views: 2414
Reputation: 41228
This answer assumes you want non-overlapping pairs. You can do this via zip()
because the iterator is consumed:
for one, two in zip(gen, gen):
# do something
Example:
>>> gen = (x for x in range(5))
>>> for one, two in zip(gen, gen): print(one,two)
...
0 1
2 3
Note, as timgeb commented, you should use itertools.zip_longest
if you have an uneven number of elements and you want the last one with a fill value, for example:
>>> gen = (x for x in range(5))
>>> for one, two in zip_longest(gen, gen): print(one, two)
...
0 1
2 3
4 None
Upvotes: 10
Reputation: 78780
Answering your updated question, use itertools.tee
to construct a second iterator, advance the second iterator once and discard the result, then loop over both iterators in pairs using zip
.
>>> from itertools import tee
>>> it = iter('abc')
>>> it1, it2 = tee(it)
>>>
>>> next(it2, None)
'a'
>>> for first, second in zip(it1, it2):
... first, second
...
('a', 'b')
('b', 'c')
Thank you. This is the cleanest, most "pythonic" way to do it? I feel the solution to this simple problem is to complex.
I don't think there is a cleaner solution. In fact, it's the pairwise
recipe from the itertools docs:
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return izip(a, b)
Upvotes: 7
Reputation: 3061
I once solved the similar problem with following :
def gen():
results = [1, 2, 3, 4, 5]
for i, v in enumerate(results):
# if i < len()
if (i + 1) < len(results):
yield (v, results[i + 1])
else:
yield v
output = gen()
for each in output:
print(each)
Output will be:
(1, 2)
(2, 3)
(3, 4)
(4, 5)
5
Upvotes: 0