カスタムPythonリストの並べ替え


93

私は私の古いコードをリファクタリングしていて、これに遭遇しました:

alist.sort(cmp_items)

def cmp_items(a, b):
    if a.foo > b.foo:
        return 1
    elif a.foo == b.foo:
        return 0
    else:
        return -1

コードは機能します(そして、私はそれを約3年前に書きました!)が、Pythonドキュメンテーションのどこにもドキュメント化されているこのことを見つけることができず、誰もがsorted()カスタムソートの実装に使用しています。これがなぜ機能するのか誰かが説明できますか?


sorted()sort()呼び出し規約の違いを法として、ほとんど同じ方法でカスタムの並べ替えを提供します。
ラッセルボロゴーブ2012

2
実際、何が起こるかというとkeycmp関数を渡すよりもパラメーターを使用する方が好ましいという ことです。(
後者

リストの項目が何であったかによりますが、あいまいです。あなたのコードはそれらが属性を持つことを要求しますfoo、そうでなければそれは爆破します。ベターカスタム定義するために__lt__()、その後、あなたのクラスのメソッドをsorted()し、list.sort()アウトオブボックスに動作します。(ところで、定義することはもはや必要ないオブジェクト__cmp__()だけを、__lt__()この参照
SMCI

回答:


60

ここに記載されています

sort()メソッドは、比較を制御するためのオプションの引数を取ります。

cmpは、2番目の引数(リストアイテム)のカスタム比較関数を指定します。これは、最初の引数が2番目の引数より小さい、等しい、または大きいかどうかに応じて、負、ゼロ、または正の数を返す必要があります:cmp = lambda x、y :cmp(x.lower()、y.lower())。デフォルト値はNoneです。


おかげでmiles82私はここでチェックしていて、メソッド署名docs.python.org/tutorial/datastructures.htmlで
Lorenzo

リンク先のページに同じテキストが表示されません。ドキュメントは変更されましたか?それに、使ってみるcmpともらえるTypeError: 'cmp' is an invalid keyword argument for this function。ここで何が起こっているのですか?
HelloGoodbye

1
@HelloGoodbye sort()には、Python 3のcmp引数がありません。これは、ドキュメントリンクがPython 2の場合の古い回答です。古いドキュメントはここにあります。詳細については、こちらをご覧ください。Python 3を使用している場合は、代わりにkey引数を使用してください
miles82

そして、実際に比較関数を提供したい場合はどうでしょうか?文字列内の数値(長さを問わず、貪欲に選択された)を記号として扱います。これは、個々の文字が他の方法で扱われるのと同等です。比較関数を提供できる場合は簡単にそれを実現する方法を知っていますが、キー関数を提供する必要がある場合はそうではありません。なぜこれが変更されたのですか?
HelloGoodbye

文字列に含まれる各数値が、レベンシュタインコーディングなど、辞書式に数値を順序付けるエンコーディングを使用してエンコードされている場合でも、達成できると思います。しかし、私は、実際の回避策として、これをより考えるsortのPython 3での引数としてではなく、私がいることを何かとして比較関数を取ることはありません、実際にやりたいです。
HelloGoodbye

104

補足として、同じ並べ替えを実装するためのより良い代替案を次に示します。

alist.sort(key=lambda x: x.foo)

または代わりに:

import operator
alist.sort(key=operator.attrgetter('foo'))

Sorting How Toを確認してください。これは非常に便利です。


1
オペレーターについてのTILは、非常に便利です。
2015年

13

この例のように。このリストを並べ替えます。

[('c', 2), ('b', 2), ('a', 3)]

出力:

[('a', 3), ('b', 2), ('c', 2)]

タプルを2番目の項目、次に最初の項目でソートする必要があります。

def letter_cmp(a, b):
    if a[1] > b[1]:
        return -1
    elif a[1] == b[1]:
        if a[0] > b[0]:
            return 1
        else:
            return -1
    else:
        return 1

最後に:

ただ sort(letter_cmp)


4
並べ替えるリストはどのようにしてわかりますか?
Cameron Monks

2
@CameronMonks yourList.sort(letter_cmp)
Minyc510

7

これはPython 3では機能しません。

functools cmp_to_keyを使用して、古いスタイルの比較関数を機能させることもできます。

from functools import cmp_to_key

def cmp_items(a, b):
    if a.foo > b.foo:
        return 1
    elif a.foo == b.foo:
        return 0
    else:
        return -1

cmp_items_py3 = cmp_to_key(cmp_items)

alist.sort(cmp_items_py3)

1

python3では次のように書くことができます:

from functools import cmp_to_key

def cmp_items(a, b):
    if a.foo > b.foo:
        return 1
    elif a.foo == b.foo:
        return 0
    else:
        return -1

alist = sorted(alist, key=cmp_to_key(cmp_items))

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.