遍历两个列表的列表推导式未按预期工作

17

我想迭代两个列表。第一个列表包含一些浏览器用户代理,第二个列表包含这些浏览器的版本。我只想筛选出那些版本大于60的用户代理。

这是我的列表理解的样子:

[link for ver in version for link in useragents if ver > 60]

这个列表的问题在于多次打印相同的用户代理。我使用 zip 函数编写了以下代码,它可以正常工作:

for link, ver in zip(useragents, version):
    if ver > 60:
        # append to list
        print(link)

为什么我的列表推导式返回意外的结果?

5个回答

28

你的第一个列表推导式等价于:

res = []
for ver in version:
    for link in useragents:
        if ver > 60:
            res.append(link)

注意您的嵌套循环时间复杂度为O(n2),即您正在遍历版本用户代理每种组合。假设您的版本用户代理列表是对齐的,那不是您想要的。

相当于您的for循环的是以下列表推导式:

res = [link for link, ver in zip(useragents, version) if ver > 60]

9
[link for (link, ver) in zip(useragents, version) if ver > 60]

您仍需将这两个列表压缩在一起。


8
这是一个HTML标签。
[link for ver in version for link in useragents if ver > 60]

“is not the same as zip”并不等同于zip。它不会同时迭代这两个序列,而是会迭代这两个序列的所有组合。

这就好像你写下了:

for ver in version:
    for link in useragents:
        if ver > 60:
            # append(link)

如果两个序列的长度都为5,则会有25种组合(其中一些由条件ver>60过滤掉)。

当您想要并行遍历序列时,即使在推导式中,zip也是实现的方式。

[link for (link, ver) in zip(useragents, version) if ver > 60]

2

或者您可以结合使用compress()函数和map()函数,其中您可以检查一些条件:

最初的回答

from itertools import compress

filter_ = map(lambda x: x > 60, version)
list(compress(useragents, filter_))

Example:

s = 'ABCDEFG'
nums = range(len(s))
    
filter_ = map(lambda x: x > 3, nums)
print(list(compress(s, filter_)))
# ['E', 'F', 'G']

1

没有您的数据,很难确定发生了什么,但通常来说,“double”列表推导不同于zip,而是双重循环,即:

[a for b in bs for a in as]

等同于

for b in bs:
    for a in as:
        lst.append(a)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接