对于具有复杂数据对象的多个列表,使用pythonic方法执行AND或NOT

2024-06-16 10:18:59 发布

您现在位置:Python中文网/ 问答频道 /正文

我有多个复杂对象的列表。我想用它们做布尔运算。你知道吗

:结果列表将包含所有已用源列表中存在的所有对象。不应该有重复的。你知道吗

:结果列表应包含所有已用源列表中的所有对象。不应该有重复的。你知道吗

:结果列表应仅包含源列表中不存在于“不”列表中的现有对象。你知道吗

#!/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对象。在我这里的例子中,他们的“身份”不是主键。他们的“身份”是建立在他们成员的共同身份的基础上的(简单的例子:“名字”,“姓氏”,“出生日期”)。你知道吗


Tags: 对象name列表def身份passpersonbob
2条回答

感谢@criket\u 007给了我正确的提示。Python太容易了!只需为complexe数据对象创建操作符。然后你可以把它们当作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))

您应该使用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__

实际上,使用内置函数比使用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]

相关问题 更多 >