2016-02-20 118 views
0

我碰到一些代码,从迪纳摩数据库取回一个反复的对象,我可以这样做:在Python中,如何为迭代对象迭代多次?

print [en["student_id"] for en in enrollments] 

然而,当我再次做类似的事情:

print [en["course_id"] for en in enrollments] 

然后第二次迭代会什么都不打印出来,因为迭代结构只能迭代一次,并且已经到了最后。 (1)如果已知只有迭代中的几个项目(2)如果我们知道会有很多项目,那么如何迭代它不止一次(比如说一百万个项目),我们不想花费很多额外的内存空间?

相关的是,我抬头看rewind,它似乎是存在的PHP和Ruby,但不是为Python?

+0

存储所有数据的唯一其他选项栏是'a,b = itertools.tee(it)',但这只有在您没有首先使用一个迭代器来使用全部/大部分数据时才有用,如果这样你最好用清单来证明你的情况。 –

回答

6

enrollments是一个发电机。无论是重新发电机,如果你需要再次重复,或将其转换到一个列表:

enrollments = list(enrollments) 

考虑到原料药经常使用发电机,以避免内存膨胀账户;一个列表必须包含它所包含的所有对象的引用,所以这些对象必须同时存在。根据需要,发电机可以逐个产生元件;一旦'student_id'密钥被提取,你的列表理解就会丢弃这些对象。

另一种方法是迭代一次,然后做全部与你想要做的每个对象的事情。因此,而不是运行两个列表内涵,运行一个常规for循环,并提取所有你在一个地方需要的数据,追加,当您去到不同的列表:

courses = [] 
students = [] 
for enrollment in enrollments: 
    courses.append(enrollment['course_id']) 
    students.append(enrollment['student_id']) 

rewind在PHP是无关的这一点; Python有fileobj.seek(0)也这样做,但文件对象不是生成器。

+0

所以我从Dynamo数据库调用中取回它......我如何重新创建它? (最好不要再打电话到数据库,因为它涉及到网络和数据库访问) –

+2

@太极者无极而生:再次拨打电话。 –

+0

有趣的是,如果我们从Dynamo数据库取回所有数据(应该类似于MongoDB),那么我们是不是已经占用了RAM中的所有内存?它不像我们正在迭代12个骰子的所有排列,所以我们不需要存储'6 ** 12'元组,在这种情况下使用生成器将节省大量内存 –

0
import itertools 
it1, it2 = itertools.tee(enrollments, n=2) 

看起来它是从这里的答案:Why can't I iterate twice over the same data? 但只有当你要遍历没有太多时间有效。

+0

**注意**:与仅列出(登记)相比,这在时间和空间上效率都较低。唯一的情况是,如果您想同时迭代,这种情况会更好。就像'it1,it2 = tee(iterator,n = 2);下(IT1);为a,b在zip(it1,it2):#做东西'。这里每次迭代只有两个值会保存在内存中。但是,如果您首先迭代'it1',那么生成的所有值将存储在链表中,使其相当于只调用list(iterator)(事实上效率不如前面所述)。 – Bakuriu

+1

如果您在开始“b”之前要耗尽'a',请不要*使用'itertools.tee()'。在这种情况下,只需使用“list(it)”。如果你在迭代过的输出上混合迭代,只使用'tee()'来最小化它必须创建的缓冲区。 –