关于python:如何删除实例列表中的“重复”

How to remove `duplicates' in list of instances

我有一个特定类的实例列表。此列表包含"重复项",即重复项共享完全相同的属性。我要删除此列表中的重复项。

我可以使用

1
2
3
4
class MyClass:

    def __eq__(self, other) :
        return self.__dict__ == other.__dict__

当然,我可以迭代整个实例列表,并逐元素比较它们以删除重复的实例,但是我想知道是否有一种更纯粹的方法可以做到这一点,最好使用in operator+list理解。


sets(无订单)

集合不能包含重复元素。list(set(content))将删除一个列表。这不是太低效,可能是更好的方法之一:p您需要为您的类定义一个__hash__函数,但对于相同的元素,它必须相同,而对于不相等的元素,它必须不同,才能起作用。注意,hash值必须遵守上述规则,否则在运行之间可能会发生变化,而不会引起问题。

index函数(稳定阶)

你可以做lambda l: [l[index] for index in range(len(l)) if index == l.index(l[index])]。这只保留列表中第一个元素。

in算子(稳定阶)

1
2
3
4
5
6
def uniquify(content):
    result = []
    for element in content:
        if element not in result:
            result.append(element)
    return result

这将继续向输出列表追加元素,除非它们已经在输出列表中。


在定位球法上再多一点。您可以通过委托给元组的散列来安全地实现散列-只需散列一个包含您要查看的所有属性的元组。您还需要定义一个行为正常的__eq__

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class MyClass:
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

    def __eq__(self, other):
        return (self.a, self.b, self.c) == (other.a, other.b, other.c)

    def __hash__(self):
        return hash((self.a, self.b, self.c))

    def __repr__(self):
        return"MyClass({!r}, {!r}, {!r})".format(self.a, self.b, self.c)

当你做了这么多tuple构造时,你可以让你的类变得不可更改:

1
2
def __iter__(self):
    return iter((self.a, self.b, self.c))

这使您可以在self上调用tuple,而不是费力地执行.a, .b, .c等操作。

然后您可以这样做:

1
2
def unordered_elim(l):
    return list(set(l))

如果您想保留订单,可以使用OrderedDict

1
2
3
4
from collections import OrderedDict

def ordered_elim(l):
    return list(OrderedDict.fromkeys(l).keys())

这应该比使用inindex更快,同时仍保留顺序。您可以这样测试它:

1
2
3
4
5
6
7
data = [MyClass("this","is a","duplicate"),
        MyClass("first","unique","datum"),
        MyClass("this","is a","duplicate"),
        MyClass("second","unique","datum")]

print(unordered_elim(data))
print(ordered_elim(data))

使用此输出:

1
2
[MyClass('first', 'unique', 'datum'), MyClass('second', 'unique', 'datum'), MyClass('this', 'is a', 'duplicate')]
[MyClass('this', 'is a', 'duplicate'), MyClass('first', 'unique', 'datum'), MyClass('second', 'unique', 'datum')]

注意,如果您的任何属性不可散列,这将不起作用,您要么需要绕过它(将列表更改为元组),要么使用像in这样的缓慢的n ^ 2方法。