web-dev-qa-db-ja.com

pythonでの ">"および "<"のカスタム定義を使用したソート

次のようなカスタム関数があるとします

def greater(a, b):
    if (a % b) % 2 == 0:
        return 1
    return 0

2つの数値を比較し、どちらが大きいかを判別する方法を定義します。この場合、関数が1 a> bを返すと、a <bになります。作り付けの<built-in function sorted> orこの定義に関して、並べ替えられた数値の配列を作成しますか?

7
user5198

Python 2.xを使用している場合、これはcmpを使用して簡単に実現できますが、0ではなく-1を返すように関数を変更する必要があります。このようなもの:

def greater(a, b):
    if (a % b) % 2 == 0:
        return 1
    return -1

x = [2,7,5,10,30,15]

print(sorted(x, cmp=greater))

ただし、Python 3.xを使用している場合は、cmpが削除されたため、少し複雑になります。数値を保持するクラスを実装し、比較演算子を上書きする__lt__(より小)および__gt__(より大きい)。このようなもの:

class my_int(int):
    def __lt__(a,b):
        return (a % b) % 2 != 0
    def __gt__(a,b):        
        return (a % b) % 2 == 0

x = [my_int(2),my_int(7),my_int(5),my_int(10),my_int(30),my_int(15)]

print (sorted(x))
9
System Down

番号。

一部のxとyの値についてはgreater(x, y) != not greater(y, x)であるため、関数は数値をソートする方法について一貫した回答を提供しません。たとえば、_(3 % 4) % 2 == 1_および_(4 % 3) % 2 == 1_も使用できます。つまり、_3 > 4_および_3 < 4_は意味がありません。 @SystemDownが提案するようなcmpスタイルの関数に変換すると、一貫性のない結果が得られます。例えば:

_>>> sorted(range(3, 6), cmp=greater)
[5, 4, 3]
>>> sorted(range(1, 6), cmp=greater)
[1, 4, 3, 5, 2]
_

同じ比較関数を使用すると、5は4より小さい場合と4より大きい場合があります。

Cmp関数は自己矛盾がない場合でも、@ zstewartによって提案された_cmp_to_key_関数を使用するなど、cmp関数は読み取りとデバッグが遅いため、何らかの方法や形式で使用しないことをお勧めします同等のキー機能。

キー関数を使用すると、関数はソートされるアイテムごとに1回だけ呼び出されるため、100万個のアイテムのリストがある場合、100万回呼び出されます。次に、ソートが進行し、キー関数の戻り値を平均してn*log(n)回比較します。 100万個の要素のリストでは、1380万回です。

代わりにcmp関数を使用する場合、n*log(n)の比較ごとに1回呼び出されます。繰り返しますが、リストに100万個の要素が含まれている場合は、1380万回です。 _cmp_to_key_を使用すると、ヘルパークラスのインスタンスを100万個インスタンス化するという追加のオーバーヘッドが発生します。

同じことを実行するこれらの関数を使用して、100万のランダムな整数のリストでテストしました。

_def cmp_func(a, b):
    if a > b:
        return -1
    Elif a < b:
        return 1
    else:
        return 0

def key_func(x):
    return -x
_

_key_func_を使用した並べ替えには1.35秒かかりましたが、_cmp_func_を使用すると2.43秒かかりました。

したがって、@ lzkataの暗黙の質問に答えるには、3.xでソートするためにcmp引数を削除することをお勧めします。

  • cmp関数は微妙な方法で一貫性のない結果を生成する傾向があり、その結果、微妙で見つけにくいバグが発生します
  • cmp関数は遅い
  • cmp関数をより良いパフォーマンスのキー関数に変換することは、ほとんど常に可能です
6
stxlvt

' System Down 'という名前のプログラマーが状況を正しく説明しています。Python 3の場合は、次のコードも使用できます。

Python 3の場合:

import functools

def greater(a, b):
if (a % b) % 2 == 0:
    return 1
return -1

x = [2,7,5,10,30,15]

print(sorted(x, key=functools.cmp_to_key(greater)))
0
Amandeep