【问题标题】:Removing duplicates in a Python list by id按 id 删除 Python 列表中的重复项
【发布时间】:2016-11-19 17:10:16
【问题描述】:

我在解析树时构建了大量高级对象。然而,在这一步之后,我必须从列表中删除重复项,我发现这个新步骤在 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 重复项的最pythonical、可靠、简短和快速的方法是什么? 如果必须更改,列表的顺序无关紧要。

【问题讨论】:

  • 想通了!删除了我的 cmets。
  • Fraction 是一个不好的例子,因为如果您尝试使用标准库类来执行此操作,则无法做到。你不能改变set 使用的规则,你可以自己构建一个类似集合的类(也许是一个围绕ID 键的字典的薄包装器)。但是,如果您实际使用的是您控制的类,则可以实现__eq__,如下所示。

标签: python list duplicates


【解决方案1】:

您应该重写__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}

【讨论】:

  • 这是一个非常方便的答案,因为我使用自己的课程;添加__hash____eq__ 应该很容易;在这种特定情况下,我可以让__hash__ 返回 id 作为实现此方法的快速方法吗(因为我的小类是私有的,只在函数执行期间存在,实际上是甚至在这个函数的主体中定义)?
  • @ThomasBaruchel 为什么要这样做? hash 函数是为对象创建哈希值的最安全方法。因为它保证为不同的变量产生随机的(在python 3中)和不同的值。
  • 我问这个是因为__hash__ 需要返回一个整数,并且在这一步中,我的类(描述树中的一个节点)没有嵌入许多可用值,而是嵌入了其他节点的列表;出于这个原因,我想知道我可以散列哪个重要的值。我试图让__hash__ 返回 id 并且效果很好(仍然比我之前的尝试快),现在使用list(set(...))。这是要走的路吗?
  • @ThomasBaruchel 它会起作用,因为您不需要哈希值,它取决于__eq__ 方法,所以只要您使用id 进行比较就没有问题。
【解决方案2】:

请小心,因为通过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)])

【讨论】:

    猜你喜欢
    • 2011-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-03
    • 2011-09-29
    • 2013-08-03
    • 2017-08-13
    • 2014-06-01
    相关资源
    最近更新 更多