比较来自2个以上列表的对象

时间:2015-08-11 21:52:57

标签: python collections comparison combinations equals

有没有办法比较超过2个列表的所有2项组合?

让我们说有一个对象:

class obj():
   def __init__():
       self.name = # some name
       self.number = random(10)
   def equals(obj):
       if self.number == obj.number:
           return True
       else: return False

list1,list2,list3....listX - 所有这些列表都包含类obj

的实例

我想比较这些列表中的所有2项组合并返回相等的对象。

如果obj list2 obj.number属性为obj,而list8 obj.number for obj1 in list1: for obj2 in list2: if obj1.equals(obj2): print obj1,obj2 con.commit() 5,那么将被退回。

对于两个列表,比较很简单:

cur.copy_expert()

但我不知道如何对更多对象列表进行比较。 你有什么建议吗?

2 个答案:

答案 0 :(得分:4)

正如您所知,使用X列表,时间复杂度将达到O(n ^ X),这远非最优(在所有列表具有相同长度= n的情况下)

现在一切都取决于你实际想要的输出。在我看来,你想要找到多个列表中存在的对象。

以更高效的方式执行此操作的一种方法是使用字典(hashmap)并遍历每个列表。根据{{​​1}}哈希对象。

这将产生类似于:self.number的内容,其中键是对象的编号,值是具有这些值的对象。

通过遍历此字典并仅考虑具有大小大于或等于2的列表的条目,您将得到相同的对象。

这里时间复杂度等于O(n * X),即~O(n)

为了说明这一点,我创建了一个使用2个列表的简短示例

{1: [obj1], 2: [obj2, obj3], 3: [obj4], ...}

它可能可以使用漂亮的python构造进行优化,但它显示了它背后的想法。

输出是:

from collections import defaultdict

class Obj():
   def __init__(self, value):
       self.number = value


def find_equals(list1,list2):
    d = defaultdict(list)
    for obj1 in list1:
        d[obj1.number].append(obj1)
    for obj2 in list2:
        d[obj2.number].append(obj2)
    return [d[i] for i in d if len(d[i]) >= 2]

def test():
    l1 = [Obj(1),Obj(2),Obj(3),Obj(4)]
    l2 = [Obj(5),Obj(2),Obj(3),Obj(6)]
    print find_equals(l1,l2)
test()

在测试样本中使用了具有数字[[<__main__.Obj instance at 0x103278440>, <__main__.Obj instance at 0x103278560>], [<__main__.Obj instance at 0x103278488>, <__main__.Obj instance at 0x1032785a8>]] 2的对象。

答案 1 :(得分:1)

(非常)简单的方法是获得对象列表的交集。 为此,您必须使对象具有可清除性,以便为每个对象列表构建一个集合。

def __hash__(self):
    return self.number

然后,要检查多个列表,只需采用集合交集:

x = [Obj(1) Obj(3) Obj(8) Obj(10) Obj(3)] 
y = [Obj(2) Obj(9) Obj(10) Obj(3)] 

intersection = x & y  # -> returns {Obj(3), Obj(10)}

此实现具有最差的案例复杂性(n - 1) * O(L),其中L是集合长度的最大值,n是集合的数量。 所以,就复杂性而言,我认为DJanssens的答案更快。

但如果表现不是问题(例如你有小名单等),我认为能够写作更优雅:

def intersect(*lists):
     return set.intersection(*map(set, lists))

或lambda表示法中的相同内容:

intersect = lambda *lists: set.intersection(*map(set, lists))