Python: 优雅地对同一列表进行双重/多重迭代的方法

6 投票
17 回答
6064 浏览
提问于 2025-04-15 11:36

我写了一段代码,目的是比较列表中的某些项目和后面其他项目之间的关系。请问有没有更优雅的方式来处理这种双重循环的情况?

jump_item_iter = (j for j in items if some_cond)
try:
    jump_item = jump_item_iter.next()
except StopIteration:
    return
for item in items:
    if jump_item is item:
        try:
            jump_item = jump_iter.next()
        except StopIteration:
            return
    # do lots of stuff with item and jump_item

我觉得“except StopIteration”这个写法不太优雅。

编辑:

为了让这个问题更清楚,我想遍历列表中的每个项目,并将它与列表中后面某个满足条件的项目(称为jump_item)配对。

17 个回答

1

我不知道 compare() 这个函数具体在干嘛,但大部分情况下(大约80%),你可以用一个简单的字典或者一对字典来解决问题。在一个列表里跳来跳去其实就是一种线性搜索。线性搜索尽量应该用直接引用(比如字典)或者树搜索(使用 bisect 模块)来替代。

1

下面这个迭代器在时间和内存使用上都很高效:

def jump_items(items):
    number_to_be_returned = 0
    for elmt in items:
        if <condition(elmt)>:
            for i in range(number_to_be_returned):
                yield elmt
            number_to_be_returned = 1
        else:
            number_to_be_returned += 1

for (item, jump_item) in zip(items, jump_items(items)):
    # do lots of stuff

请注意,你可能实际上想把第一个返回的数字设置为1...

4

从我所看到的,现有的解决方案都适用于一次性使用的迭代器,可能是无限的,但它们似乎都需要一个可迭代的对象。

这里有一个解决方案。

def batch_by(condition, seq):
    it = iter(seq)
    batch = [it.next()]
    for jump_item in it:
        if condition(jump_item):
            for item in batch:
                yield item, jump_item
            batch = []
        batch.append(jump_item)

这个方法可以轻松处理无限迭代器:

from itertools import count, islice
is_prime = lambda n: n == 2 or all(n % div for div in xrange(2,n))
print list(islice(batch_by(is_prime, count()), 100))

这个代码会打印出前100个整数以及跟在它们后面的质数。

撰写回答