我有多个包含复杂对象的列表。我想对它们进行布尔操作 AND , OR , NOT 。
AND :结果列表将包含所有使用的源列表中存在的所有对象。应该没有重复。
OR :结果列表应包含所有已使用源列表中的所有对象。应该没有重复。
不:结果列表应仅包含源列表中不存在于非列表中的现有对象。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# the "complex data"
class Person:
def __init__(self, name):
# assume the 'name' as unique
self.name = name
# create example data
mylistA = [Person('Anna'),
Person('Bob'),
Person('Jane'),
Person('Alfred')]
mylistB = [Person('Simon'),
Person('Anna'),
Person('Doris'),
Person('Bob')]
mylistC = [Person('Bob'),
Person('Rosi'),
Person('Becky'),
Person('Anna')]
mylistD = [Person('Alfred'),
Person('Bob'),
Person('Chris'),
Person('Susi')]
def doAND(some_lists):
pass
def doOR(some_lists):
pass
def doNOT(one_list, not_list):
pass
# should result in 'Anna', 'Bob'
resultAND = doAND([mylistA, mylistB, mylistC])
print(resultAND)
# should result in 'Anna', 'Bob', 'Jane', 'Alfred', 'Simon', 'Doris', 'Rosi',
# 'Becky'
resultOR = doOR([mylistA, mylistB, mylistC])
print(resultOR)
# 'Anna'
resultNOT = doNOT(resultAND, mylistD)
print(resultNOT)
背景资料:"复杂对象"在真实场景中是sqlalchemy对象。他们的身份"在我的例子的上下文中,这不是主键。他们的身份"是基于成员的共同形成(简单的例子:"名字","姓氏","生日和#34;)。
答案 0 :(得分:1)
这是您可以考虑的建议。将list
表示为dict
。这使得执行这些基于集合的操作变得更容易(在一定程度上)。
mydictA = {x.name : x for x in mylistA }
无论如何,回到原来的问题。 doAND
基本上是交叉操作。 doOR
是一个联盟,doNOT
是一个差异操作。
以下是doAND
的示例。你应该能够弄清楚其余部分。
def doAND(list1, list2):
dict1 = {x.name : x for x in list1}
dict2 = {x.name : x for x in list2}
common_names = set(dict1.keys()).intersection(set(dict2.keys()))
return [dict1[x] for x in common_names if x in dict1] + [dict2[x] for x in common_names if x in dict2]
对于doOR
,您需要set1.union(set2)
,对于doNOT
,您应该set1 - set2
。
希望这有帮助。
答案 1 :(得分:1)
您应该使用set而不是列表。 这样可以避免重复,并以方便的方式提供所有操作:
a=[1,2,3,4,5]
b=[1,2,3]
a=set(a)
b=set(b)
# OR
a | b # [1,2,3,4,5]
# AND
a & b # [1,2,3]
# NOT
a - b # [4,5]
即使对于复杂的数据类型,您也可以使用它。他们需要满足两个标准:
__eq__
需要实施__hash__
需要实施该集需要__eq__
来查找重复项。但是,如果您只实施__eq__
,则会删除默认的__hash__
实施。
这是因为__eq__
和__hash__
需要保持一致。
所以你需要重新实现__hash__
您对内置hash()
函数的使用实际上比使用hashlib的版本好得多。所以我更新了。
令人惊讶的是,__hash__
的实现并未提供__eq__
的隐式实现,即使具有相同散列的对象必须相等也是不变的。因此,__eq__
和__hash__
都需要实施。在此答案的先前版本中,这是错误的。
由于性能原因,可能需要再次实施__eq__
运算符。我不知道hash()
函数的速度有多快,但如果你的集合变大,那么直接比较名称可能是一种有用的优化,而不是先对它们进行散列。
class Person:
def __init__(self, name):
# assume the 'name' as unique
self.name = name
def __hash__(self):
return hash(self.name)
def __eq__(self, other):
return self.name == other.name
# return hash(self) == hash(other)
def __repr__(self):
return self.name
persons = [Person("a"), Person("b"), Person("a")]
print(persons) # [a, b, a]
persons_set= set(persons)
print(persons_set) # [a, b]
答案 2 :(得分:1)
感谢@ criket_007给了我正确的提示。 Python非常简单!只需为 complexe数据对象创建运算符。然后,您可以将它们视为order/allow/deny
。
这是更新的例子
set