您可以使用grouper recipe,izip(*[iterator]*2)将线条df分成 2 组。然后,要找到最小的线条对,使用min及其key参数来指定用于比较的代理。在这种情况下,对于每一对行,(p, l)我们希望使用第二行的浮点数float(l),作为代理:
import itertools as IT
with open('filepath') as df:
previous, minline = min(IT.izip(*[df]*2),
key=lambda (p, l): float(l))
minline = float(minline)
print(previous)
print(minline)
印刷
Over
0.5678
石斑鱼食谱的解释:
要了解石斑鱼配方,首先看看如果df是一个列表会发生什么:
In [1]: df = [1, 2]
In [2]: [df]*2
Out[2]: [[1, 2], [1, 2]]
在 Python 中,当您将列表乘以一个正整数时n,您将获得n列表中项目的(浅)副本。因此,[df]*2制作一个包含两个副本的列表df。
现在考虑zip(*[df]*2)
*使用的 in具有zip(*...)特殊的含义。它告诉 Python 解压缩*要传递给的 into 参数之后的列表zip。因此,zip(*[df]*2)完全等价于zip(df, df):
In [3]: zip(df, df)
Out[3]: [(1, 1), (2, 2)]
In [4]: zip(*[df]*2)
Out[4]: [(1, 1), (2, 2)]
SaltyCrane 在这里给出了参数解包的更完整的解释。
记下正在做什么zip。
zip(*[df]*2)剥离两个副本的第一个元素(在这种情况下都是 1),并形成元组 (1,1)。然后它剥离两个副本的第二个元素(两个 2),并形成元组 (2,2)。它返回一个包含这些元组的列表。
现在考虑当df是迭代器时会发生什么。迭代器有点像列表,除了迭代器只适用于单次传递。当项目被拉出迭代器时,迭代器永远不能倒带。
例如,文件句柄是一个迭代器。假设我们有一个带有行的文件
1
2
3
4
In [8]: f = open('data')
f您可以通过调用将项目从迭代器中拉出next(f):
In [9]: next(f)
Out[9]: '1\n'
In [10]: next(f)
Out[10]: '2\n'
In [11]: next(f)
Out[11]: '3\n'
In [12]: next(f)
Out[12]: '4\n'
每次调用时next(f),我们都会从文件句柄中获取下一行f. 如果我们next(f)再次调用,我们会得到一个 StopIteration 异常,表明迭代器是空的。
现在让我们看看石斑鱼食谱的表现如何f:
In [14]: f = open('data') # Notice we have to open the file again, since the old iterator is empty
In [15]: [f]*2
Out[15]:
[<open file 'data', mode 'r' at 0xa028f98>,
<open file 'data', mode 'r' at 0xa028f98>]
[f]*2给我们一个列表,其中包含同一个迭代器的两个相同副本f。
In [16]: zip(*[f]*2)
Out[16]: [('1\n', '2\n'), ('3\n', '4\n')]
zip(*[f]*2)从第一个迭代器中f剥离第一项,然后从第二个迭代器中剥离第一项f。但是迭代器f两次都是一样的!而且由于迭代器适合单次通过(您永远无法返回),因此每次剥离一个项目时都会得到不同的项目。每次zip都打电话来剥一个项目。next(f)所以第一个元组是
('1\n', '2\n'). 同样,zip然后从第一个迭代器中剥离下一项,f从第二个迭代器中剥离下一项f,并形成元组('3\n', '4\n')。因此,zip(*[f]*2)返回
[('1\n', '2\n'), ('3\n', '4\n')]。
这就是石斑鱼食谱的全部内容。上面,我选择使用IT.izip而不是zip这样 Python 会返回一个迭代器而不是一个元组列表。如果文件中有很多行,这将节省大量内存。zip和之间的区别在这里IT.izip得到更全面的解释。