【问题标题】:Iterate over two iterators in parallel without using Python's zip function?在不使用 Python 的 zip 函数的情况下并行迭代两个迭代器?
【发布时间】:2019-09-25 08:30:24
【问题描述】:

在 python 中,并行迭代到迭代器的惯用方式是使用“zip”函数。

Python 3.6.5 (default, Mar 31 2018, 19:45:04) [GCC] on linux
>>> it1 = range(0,5)
>>> it2 = range(3,10)
>>> for x1, x2 in zip(it1, it2): print('', x1, x2, sep='\t')
... 
        0       3
        1       4
        2       5
        3       6
        4       7
>>> it1 = range(0,5)
>>> it2 = range(3,10)
>>> [ 100*x1 + x2 for x1,x2 in zip(it1,it2) ]
[3, 104, 205, 306, 407]

但是,我不喜欢这里的模式,它将项目到名称的分配与压缩迭代中的项目顺序分离:在更复杂的示例中,可能很容易产生诸如

之类的错误
for apple1, apple2, orange in zip(apples, oranges, more_apples): ...

因此我想知道是否存在一种模式,它允许类似于

for apple1 in apples,\
    apple2 in oranges,\
    orange in more_apples: ...

这样的错误会更明显。

对于列表推导,存在外观相似的语法,但对应于 itertools.product() 而不是 zip()

【问题讨论】:

  • 作为与问题无关的评论:it1 = range(0,5) 之类的行不必多次使用,因为它们不是生成器,并且不会筋疲力尽。至于您的问题,解决方法是在第一个列表上使用 enumerate,并通过索引从其他列表中获取元素。
  • 我想使用for i in range(len(apples)): apples[i], oranges[i], ... 是一种选择,但处理不同的长度不会像使用zip 那样优雅。
  • @Chris 如果苹果、橙子是迭代器(不能被索引)并且预期的元素数量使得包装到可索引容器中不可行,它也不起作用。
  • 投反对票时,请评论为什么

标签: python iterator iteration generator


【解决方案1】:

怎么样:

[100 * it1[i] + it2[i] for i in range(min(len(it1), len(it2)))]

【讨论】:

  • 这使得元素和可迭代对象之间的距离更大(OP试图最小化)
  • 其实在具体的玩具例子中是可以的,但是当it1、it2没有绑定名字,或者是通用迭代器(不能被索引)时,就崩溃了。
  • @DeepSpace 从我从问题中了解到,他的问题是他可能会对zip 内外的项目顺序感到困惑,这会导致错误,而在我的解决方案中有range(min(len... 函数中的迭代顺序没有意义
【解决方案2】:

如果您的条目是长度相等的列表,您可以使用 pandas DataFrame 完成您想要的。

使用zip,您可以执行以下操作:

l1 = ['a', 'b','c']
l2 = ['A','B','C']

result = [e1+' '+e2 for e1, e2 in zip(l1, l2)]
print(result)

得到

['a A', 'b B', 'c C']

或者,您可以将两个列表组合成一个pd.DataFrame,如下所示:

df = pd.DataFrame({'l1': l1, 'l2':l2})

(请注意,您仍然必须为每个列表多使用一个名称,但该行确实在 l1 旁边有 'l1',这与 zip 的用法不同)。

现在,您可以简单地使用

遍历数据框中的行(或做其他事情......)
result = [row['l1']+' '+row['l2'] for _, row in df.iterrows()]

这会给出相同的结果。

【讨论】:

  • 一些主要缺点:(a) 冗长。但这可以改进为[ f'{r.l1} {r.l2}' for _, r in pandas.DataFrame({'l1': l1, 'l2': l2}).iterrows() ](b) 依赖项。 添加一个像 pandas 这样的主要依赖项只是为了滥用它,我觉得这不是一个好主意。 (c) 不同的语义。 要求迭代器具有相同的长度,并且该长度要求有限。此外,该结果必须足够小以使表格能够放入内存。
  • 这个想法很有趣:我想要的可以通过返回某种记录或collections.namedtuple 的自定义“zip”函数来实现,这样它就可以用作[ f(t.l1, t.l2) for t in namedzip(l1=iter1, l2=iter2)]。不过为了代码的可读性,如果内置 zip 函数支持它,我仍然更喜欢。
  • 我不会称其为滥用(将两个数组对齐在一起正是数据框的用途),我不认为内联数据框定义对可读性有好处,但大问题确实是语义 - 长度相同,长度有限,所有这些问题。
  • 如果有内置的zip功能支持肯定会更好;我只是不认为有这样的解决方案。
猜你喜欢
  • 2019-01-12
  • 2018-12-31
  • 1970-01-01
  • 1970-01-01
  • 2012-03-02
  • 2014-08-07
  • 2021-10-05
  • 2020-10-14
相关资源
最近更新 更多