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__since cmp(x, y)returns -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

これが 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 に答える