Python:any()检查对象列表中的属性是否与列表匹配

时间:2017-10-20 14:09:13

标签: python data-structures iterator generator

我有一个从SQLAlchemy Query

返回的对象列表
projects =
    [
        {'project_id': 1, 'project_name': 'A'},
        {'project_id': 2, 'project_name': 'B'},
        {'project_id': 3, 'project_name': 'C'},
        {'project_id': 4, 'project_name': 'D'},
        {'project_id': 5, 'project_name': 'E'},
        {'project_id': 6, 'project_name': 'F'}
    ]

我想确保对象列表在此列表中具有项目名称:

project_list = ['A', 'B', 'C']

如果它只是一个值,我可以使用

any(p.project_name == "A" for p in projects)

如何与List进行类似的比较?类似的东西:

any(p.project_name in project_list for p in projects)

上面的代码有效,但我怀疑只要有一个匹配,any()就会返回True

解决方法

现在,我将对象属性提取到一个新列表中,将两个列表转换为集合并进行比较。

project_names = [project.project_name for project in projects]
assert set(project_list) <= set(project_names)

这样可行,但对于复杂的对象和长列表来说效率很低。

4 个答案:

答案 0 :(得分:2)

通过set进行此操作的方式很好,并且比任何嵌套循环方法都要好得多。为什么你认为它效率低下?

次要优化是直接通过生成器表达式创建项目集,而不是提取临时列表:

project_set = set(p.project_name for p in projects)

然后使用all而不是project_list

assert all(p in project_set for p in project_list)

答案 1 :(得分:1)

您可以使用all

all(any(p_name==p.project_name for p in projects) for p_name in projects_list)

或更具可读性:

appears = lambda p_name: any(p_name==p.project_name for p in projects)
all(appears(p_name) for p_name in projects_list)

答案 2 :(得分:0)

如果您确实需要短路行为:遍历对象列表;每当你找到一个你关心的一个添加到一个集合;一旦该集合完整返回True;否则返回False

def f(projects, project_list):
    project_list = set(project_list)
    seen = set()
    for p in projects:
        if p.project_name in project_list:
            seen.update(p.project_name)
            if seen == project_list:
                return True
    return False

对不起,没有简洁的单行。

答案 3 :(得分:0)

您可能喜欢以下内容

'Project name' in [p.project_name for p in projects]