【问题标题】:python set intersection with object setspython设置与对象集的交集
【发布时间】:2012-04-12 01:20:52
【问题描述】:

我正在使用 amazon boto,我有 2 个列表。列表 1 包含 Instance 对象。清单 2 包含 InstanceInfo 对象。这两个对象都有一个名为 id 的属性。我需要获取 InstanceInfo 列表中存在 id 的 Instance 对象列表。

l1 = [Instance:i-04072534, Instance:i-06072536, Instance:i-08072538, Instance:i-0a07253a, Instance:i-e68fa1d6, Instance:i-e88fa1d8, Instance:i-ea8fa1da, Instance:i-ec8fa1dc]

l2 = [InstanceInfo:i-ec8fa1dc, InstanceInfo:i-ea8fa1da, InstanceInfo:i-e88fa1d8, InstanceInfo:i-e68fa1d6]

想要的结果:

l3 = [Instance:i-ec8fa1dc, Instance:i-ea8fa1da, Instance:i-e88fa1d8, Instance:i-e68fa1d6]

现在我已经解决了:

l3= []
for a in l1  
    for b in l2:
        if a.id == b.id:
            l3.append(a)

但是,有人告诉我,我应该使用设置交集来替换它。我一直在看例子,它看起来非常简单。但是我没有看到任何使用对象的示例。

我已经玩了一段时间,理论上我可以看到它工作,但可能有一些我可能不知道的“高级”语法。我还在学习python。

【问题讨论】:

    标签: python amazon-ec2 set intersection boto


    【解决方案1】:

    这比 Marcin 的回答更快(虽然相似):

    ids_l1 = set(x.id for x in l1)  # All ids in list 1
    intersection = [item for item in l2 if item.id in ids_l1]  # Only those elements of l2 with an id in l1
    

    预先计算 ids_l1 并且不要写 if item.id in set(…) 很重要,因为每次都会重新构建集合(因为要为每个元素 item 重新评估完整的测试表达式)。

    Python 集为您提供快速的元素成员资格测试 (in)。这样的测试用集合比用列表快得多(因为列表的元素必须一个一个地读取,而集合的元素是“散列的”)。

    【讨论】:

    • 你是对的,因为相交不在列表创建范围内。但是 Marcin 的解决方案是最慢的。
    • @MateuszWoźniak 我毫不怀疑您的解决方案将是最慢的;您的想法只是说“结果:未运行”,这可能是最好的,因为您甚至不使用通常的 timeit 库,而是基于系统时间的解决方案。
    • 这行得通,但这段代码和 Mateusz 的代码有什么区别?除了这个使用 set() 并且看起来更快?
    • @Marcin 去创建更好的测试并将链接粘贴到它:)
    • @MateuszWoźniak:我明白你的意思:在 Marcin 的回答中,交叉点的计算是针对 l2 中的每个元素重做的,这会减慢速度。
    【解决方案2】:

    您的方法对于小型列表可能相对有效。

    使用集合,您必须提取 id,计算 id 的交集,然后将项目收集到新列表中。比如:

    set1 = set(x.id for x in l1)
    set2 = set(x.id for x in l2)
    intersection_ids = set1 & set2
    intersection_list = [item for item in l2 if item.id in intersection_ids]
    

    您可以通过扫描较短的列表或将对象存储在字典中来提高效率。

    【讨论】:

    • 不投反对票,因为集合 元素查找速度很快。但是,确实没有必要通过列表l2 两次(在set(…)for item in l2 中),如我的回答所示。
    【解决方案3】:

    试试这个:

    # get ids of elements in second list
    l2_ids = [x.id for x in l2]
    # get elements from first list that have ids in second
    l3 = [x for x in l1 if x.id in l2_ids]
    

    【讨论】:

    • -1 除非保证列表非常非常小,否则为什么要测试列表中的成员资格?
    • 这是获取 Kevin 在他的问题中发布的列表相交的快速方法。它有效,所以我不知道你为什么推-1。但好吧,这是你的意见。
    • in 测试很慢:这个算法在 O(n_l1 * n_l2) 中。当 Python 提供一些快速简单的解决方案(如 Marcin 的)时,我不建议使用慢速算法。
    • 所以在您的控制台中试试这个:ideone.com/o8Xa1 相交集更昂贵
    • 10000 个元素是小列表?在您的代码中,您在理解列表的每个步骤中都创建了两个集合的联合,因此这总是比简单的 in 慢,这当然也比在外部创建集合要慢(正如 EOL 所写)。
    猜你喜欢
    • 2020-03-31
    • 1970-01-01
    • 1970-01-01
    • 2019-02-04
    • 2015-02-06
    • 2012-03-05
    • 1970-01-01
    • 2021-09-14
    • 1970-01-01
    相关资源
    最近更新 更多