通过id删除Python列表中的重复项

时间:2016-11-19 08:41:12

标签: python list duplicates

我在解析树时构建了大量高级对象列表。但是,在这一步之后,我必须从列表中删除重复项,并且我在Python 2中发现这个新步骤非常慢(它可以接受,但在Python 3中仍然有点慢)。但是我知道不同的对象实际上有一个不同的 id 。出于这个原因,我设法通过以下步骤获得更多更快的代码:

  • 在解析时将所有对象附加到列表中;
  • 使用key=id选项对列表进行排序;
  • 遍历排序列表,如果前一个元素具有相同的id,则删除一个元素。

因此,我有一个现在可以顺利运行的工作代码,但我想知道我是否可以在Python中更直接地完成这项任务。

示例。让我们构建两个具有相同值但具有不同 id 的相同对象(例如,我将按顺序执行fractions.Fraction依赖标准库):

from fractions import Fraction
a = Fraction(1,3)
b = Fraction(1,3)

现在,如果我尝试通过使用pythonical list(set(...))来实现我想做的事情,我会得到错误的结果,因为{a,b}只保留两个值中的一个(相同但有不同的值) ID )。

我现在的问题是: id 删除重复内容的最快速,最可靠,最简短,最快捷的方法是什么,而不是 value 重复? 如果必须更改列表的顺序并不重要。

2 个答案:

答案 0 :(得分:4)

您应该覆盖__eq__方法,以便它取决于对象id而不是其值。但请注意,您的对象也必须是可以清理的,因此您也应该定义一个正确的__hash__方法。

class My_obj:
    def __init__(self, val):
        self.val = val

    def __hash__(self):
        return hash(self.val)

    def __eq__(self, arg):
        return id(self) == id(arg)

    def __repr__(self):
        return str(self.val)

演示:

a = My_obj(5)
b = My_obj(5)

print({a, b})
{5, 5}

答案 1 :(得分:3)

要小心,因为id的描述可能会因某些基本类型而失败,其中python会在可能的情况下优化存储:

a = "foo"
b = "foo"
print(a is b)

产量

True

无论如何,如果你想处理标准对象(甚至是不可清洗的对象),你可以将它们存储在以id为键的字典中。

分数示例:

from fractions import Fraction
a = Fraction(1,3)
b = Fraction(1,3)

d = dict()

d[id(a)] = a
d[id(b)] = b

print(d.values())

结果:

dict_values([Fraction(1, 3), Fraction(1, 3)])