通过元组属性过滤两个对象列表

时间:2015-07-13 11:18:46

标签: python

我有两个列表对象,我只希望list1中的那些元素具有与list2中的元组属性匹配的属性元组:

list1= [ojec1, objec2, objec3,....]

list2=[fig1,fig2,fig3,...]

for i in range (len(list1)):
  for j in range (len(list2)):
    if (list1[i].attr1==list2[j].attr1 & list1[i].attr2==list2[j].attr2):
      ...

有更快的方法吗?

4 个答案:

答案 0 :(得分:3)

由于嵌套的for循环,您的原始代码需要range(len(...))步(quadratic time)来查找匹配的元素。

它还使用and和数字索引,只需迭代元素就可以清除它们! (请参阅first example here获取解释)

此外,对于“逻辑和”,您需要使用&运算符,而不是O(N)(正如Kasra所说的那样是“按位AND”)。

所以,为了使这个更清洁,更有效(class Something(object): def __init__(self, a, b): self.a = a self.b = b def __repr__(self): return "Something(%s, %s)" % (self.a, self.b) l1 = [Something(1,1), Something(1,2), Something(1,3)] l2 = [Something(1,2), Something(2,2), Something(3,2)] matches = {} for obj in l1 + l2: k = (obj.a, obj.b) if k not in matches: matches[k] = [] matches[k].append(obj) for m in matches: if len(matches[m]) > 1: print "Match:", matches[m] ,线性时间),我会做以下事情:

  • 遍历两个列表
  • 上创建您需要匹配的属性的元组
  • 使用字典跟踪具有匹配元组的所有对象

以下是代码:

Match: [Something(1, 2), Something(1, 2)]

输出:

os.path.join(BASE_PATH, 'staticfiles')

答案 1 :(得分:2)

首先&是按位的,对于逻辑而言,您需要使用and。然后您不需要使用len并且在for中使用额外的索引循环遍历可迭代的项目,你可以简单地做:

for i in list1:
  for j in list2:

但是,作为一种更有效的方法,您可以使用itertools.product获取列表项之间的所有对并检查条件。

from itertools import product

for i,j in product(list1,list2):
    if (i.attr1==j.attr1 and i.attr2==j.attr2):

答案 2 :(得分:1)

如果列表2和列表1的大小都是n,那么这将是平均O(n)和O(n ^ 2)最坏情况。

from collections import namedtuple


def main():
    # Item can be any class of your choice.
    # For simplcity I just used a named tuple.
    Item = namedtuple("item", ["a", "b"])

    l1 = [Item(1,1), Item(1,2), Item(1,2), Item(2, 2), Item(1,3)]
    l2 = [Item(1,2), Item(2,2), Item(3,2)]

    # O(n) time on average and O(n^2) worst case to create a set
    attributes_of_l2 = {(item.a, item.b) for item in l2}

    # Checking match is O(1) (average case, O(n) worst case)
    # Therefore, this takes O(n) time on average and O(n^2) worst case.
    items_to_keep = [item for item in l1 if (item.a, item.b) in attributes_of_l2]

    print(items_to_keep)


if __name__ == '__main__':
    main()

输出:

[item(a=1, b=2), item(a=1, b=2), item(a=2, b=2)]

有关检查项目是否在集合中的时间复杂性,请参阅https://wiki.python.org/moin/TimeComplexity

答案 3 :(得分:0)

改善运行时的一种方法是优化属性的匹配操作。

迭代list1并将其属性存储在哈希中作为键。迭代list2并在早期哈希中查找属性键并执行您的操作。