[英]How to use Python iterators elegantly
我試圖更多地使用迭代器來循環,因為我聽說它比索引循環更快。 我不確定的一件事是如何很好地對待序列的結束。 我能想到的方法是使用try
和except StopIteration
,這對我來說看起來很難看。
更具體地說,假設我們被要求打印兩個排序列表a
和b
的合並排序列表。 我會寫下面的內容
aNull = False
I = iter(a)
try:
tmp = I.next()
except StopIteration:
aNull = True
for x in b:
if aNull:
print x
else:
if x < tmp:
print x
else:
print tmp,x
try:
tmp = I.next()
except StopIteration:
aNull = True
while not aNull:
print tmp
try:
tmp = I.next()
except StopIteration:
aNull = True
你會如何編碼使它更整潔?
我認為更加對稱地處理a
和b
會使它更容易閱讀。 此外,使用Python 2.6中的內置next
函數使用默認值可以避免處理StopIteration
的需要:
def merge(a, b):
"""Merges two iterators a and b, returning a single iterator that yields
the elements of a and b in non-decreasing order. a and b are assumed to each
yield their elements in non-decreasing order."""
done = object()
aNext = next(a, done)
bNext = next(b, done)
while (aNext is not done) or (bNext is not done):
if (bNext is done) or ((aNext is not done) and (aNext < bNext)):
yield aNext
aNext = next(a, done)
else:
yield bNext
bNext = next(b, done)
for i in merge(iter(a), iter(b)):
print i
以下函數概括了為任意多個迭代器工作的方法。
def merge(*iterators):
"""Merges a collection of iterators, returning a single iterator that yields
the elements of the original iterators in non-decreasing order. Each of
the original iterators is assumed to yield its elements in non-decreasing
order."""
done = object()
n = [next(it, done) for it in iterators]
while any(v is not done for v in n):
v, i = min((v, i) for (i, v) in enumerate(n) if v is not done)
yield v
n[i] = next(iterators[i], done)
你錯過了迭代器的全部內容。 你不要手動調用I.next()
,你只是迭代I
。
for tmp in I:
print tmp
編輯
要合並兩個迭代器,請使用itertools
模塊中非常方便的函數。 你想要的可能是izip
:
merged = []
for x, y in itertools.izip(a, b):
if x < y:
merged.append(x)
merged.append(y)
else:
merged.append(y)
merged.append(x)
再次編輯
正如評論中指出的那樣,這實際上不起作用,因為列表中的多個項目可能比列表b中的下一個項目小。 但是,我意識到還有另一個內置heapq.merge
可以解決這個問題: heapq.merge
。
sorted
的函數與列表和迭代器一起使用。 也許它不是你想要的,但以下代碼可行。
a.expand(b)
print sorted(iter(a))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.