4

在实现类的__eq____lt__方法时,通常使用元组对要比较的值进行分组,如下所示:

@total_ordering
class Foo(object):
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

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

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

    def __lt__(self, other):
        return (self.c, self.a, self.b) < (other.c, other.a, other.b)

然而,这使用了每个键的自然顺序。如果我想改变,例如,如何a排序?

到目前为止,这是我想出的,虽然它似乎工作正常,但我想知道是否有更好的方法来解决它:

@total_ordering
class Foo(object):
    def __init__(self, a, b, c):
        self.a = MyA(a) # Note
        self.b = b
        self.c = c

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

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

    def __lt__(self, other):
        return (self.c, self.a, self.b) < (other.c, other.a, other.b)

class MyA(A):
    def __hash__(self):
        # ...

    def __eq__(self, other):
        # ...

    def __lt__(self, other):
        # ...

子类化A让我可以定义我的自定义排序,并允许MyA以其他所有方式表现得像一个常规A的,这很好,但它似乎是浪费/不必要的冗长,特别是如果我必须为多个字段执行此操作。

编辑:根据user1320237下面的回答,这就是我想出的:

@total_ordering
class Foo(object):
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

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

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

    def __lt__(self, other):
        return (0, 0, 0) > (cmp(self.c, other.c),
                            cmpA(self.a, other.a),
                            cmp(self.b, other.b))

def cmpA(a1, a2):
    # ...

(注意>in __lt__sincecmp(x, y)返回-1ifx < y__lt__should return True

4

2 回答 2

5

例如,如果您想使用 list.sort() 进行排序,您可以将参数传递给它:

你的代码:

...
    def __lt__(self, other):
        return (self.c, self.a, self.b) < (other.c, other.a, other.b)

...
list.sort()

相等的:

list.sort(key = lambda self: (self.c, self.a, self.b))

也等价:

list.sort(cmp = lambda self, other: \
                (self.c, self.a, self.b) < (other.c, other.a, other.b))

因此,如果您想以不同的方式对答案进行排序,我建议:

class Foo(object):
    @staticmethod
    def cmp_absoluteOrder(self, other):
        return (self.c, self.a, self.b) < (other.c, other.a, other.b)

    @staticmethod
    def cmp_otherOrder(self, other):
        return ...

    @staticmethod
    def cmp_combinedSort(cmpA, cmpB, cmpC):
        return lambda self, other: (0, 0, 0) < (cmpA(self.c, other.c), cmpA(self.a, other.a), cmpA(self.b, other.b), )

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

...
list.sort(cmp = Foo.cmp_absoluteSorting)
list.sort(cmp = Foo.cmp_combinedSort(cmp, (lambda a1, a2: ...), cmp))

hashA = hash # or replace it if important # but the same a will retunrn the same hash

或类似的东西

于 2012-05-08T19:03:42.010 回答
1

如果这只是一次性操作,则类似以下的操作将起作用:

def custom_sorter(foo):
   """Takes Foo objects and gives a representation for sorting."""
   return (foo.c, A(foo.a), foo.b)

sorted(foo_list, key=custom_sorter)

如果要多次执行,您可以考虑使用Foo可扩展的类方法并生成类似于custom_sorter.

如果您多次使用相同的自定义分拣机,为什么不将其作为课程的一部分呢?

你真的只需要问自己为什么我真的需要

于 2012-05-08T16:16:09.887 回答