以 pythonic 方式对具有复杂数据对象的多个列表执行 AND、OR、NOT
Do AND, OR, NOT for multiple lists with complex data objects the pythonic way
我有多个包含复杂对象的列表。我想对它们进行布尔运算 AND、OR、NOT。
AND:结果列表将包含 all 使用的源列表中存在的所有对象。不能重复。
OR:结果列表应包含来自所有使用的源列表的所有对象。不能重复。
NOT:结果列表应仅包含源列表中不存在于非列表中的现有对象。
#!/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)
背景信息:"complex objects"在真实场景中是sqlalchemy对象。他们的 "identity" 在我这里的例子的上下文中不是主键。他们的 "identity" 是根据他们成员的组合形成的(简单示例:"firstname"、"lastname"、"birthdate")。
您应该使用 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]
感谢@criket_007给了我正确的提示。 Python就是这么简单!只需为 复杂数据对象 创建运算符。然后你可以把它们当作set
.
这是更新后的例子
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# the "complex data"
class Person:
def __init__(self, name):
# assume the 'name' as unique
self.name = name
def __str__(self):
return self.name
def __repr__(self):
return '{}:{}'.format(id(self), self.__str__())
def __hash__(self):
return hash(self.name)
# create example data
mylistA = [Person('Anna'),
Person('Bob'),
Person('Jane'),
Person('Alfred')]
sa = set(mylistA)
mylistB = [Person('Simon'),
Person('Anna'),
Person('Doris'),
Person('Bob')]
sb = set(mylistB)
mylistC = [Person('Bob'),
Person('Rosi'),
Person('Becky'),
Person('Anna')]
sc = set(mylistC)
mylistD = [Person('Alfred'),
Person('Bob'),
Person('Chris'),
Person('Susi')]
sd = set(mylistD)
# should result in 'Anna', 'Bob'
resultAND = sa.intersection(sb, sc)
print('AND: {}\n'.format(resultAND))
# should result in 'Anna', 'Bob', 'Jane', 'Alfred', 'Simon', 'Doris', 'Rosi',
# 'Becky'
resultOR = sa.union(sb, sc)
print('OR: {}\n'.format(resultOR))
# 'Anna'
resultNOT = resultAND.difference(sd)
print('NOT: {}\n'.format(resultNOT))
我有多个包含复杂对象的列表。我想对它们进行布尔运算 AND、OR、NOT。
AND:结果列表将包含 all 使用的源列表中存在的所有对象。不能重复。
OR:结果列表应包含来自所有使用的源列表的所有对象。不能重复。
NOT:结果列表应仅包含源列表中不存在于非列表中的现有对象。
#!/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)
背景信息:"complex objects"在真实场景中是sqlalchemy对象。他们的 "identity" 在我这里的例子的上下文中不是主键。他们的 "identity" 是根据他们成员的组合形成的(简单示例:"firstname"、"lastname"、"birthdate")。
您应该使用 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]
感谢@criket_007给了我正确的提示。 Python就是这么简单!只需为 复杂数据对象 创建运算符。然后你可以把它们当作set
.
这是更新后的例子
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# the "complex data"
class Person:
def __init__(self, name):
# assume the 'name' as unique
self.name = name
def __str__(self):
return self.name
def __repr__(self):
return '{}:{}'.format(id(self), self.__str__())
def __hash__(self):
return hash(self.name)
# create example data
mylistA = [Person('Anna'),
Person('Bob'),
Person('Jane'),
Person('Alfred')]
sa = set(mylistA)
mylistB = [Person('Simon'),
Person('Anna'),
Person('Doris'),
Person('Bob')]
sb = set(mylistB)
mylistC = [Person('Bob'),
Person('Rosi'),
Person('Becky'),
Person('Anna')]
sc = set(mylistC)
mylistD = [Person('Alfred'),
Person('Bob'),
Person('Chris'),
Person('Susi')]
sd = set(mylistD)
# should result in 'Anna', 'Bob'
resultAND = sa.intersection(sb, sc)
print('AND: {}\n'.format(resultAND))
# should result in 'Anna', 'Bob', 'Jane', 'Alfred', 'Simon', 'Doris', 'Rosi',
# 'Becky'
resultOR = sa.union(sb, sc)
print('OR: {}\n'.format(resultOR))
# 'Anna'
resultNOT = resultAND.difference(sd)
print('NOT: {}\n'.format(resultNOT))