2012-11-21 19 views
8

さまざまなコンパレータ関数を使用して辞書内のアイテムを注文したいと考えています。 下のサンプルコードをご覧ください。 cmpRatio関数を使ってsorted()が動作しない最後の部分です。私は何が間違っているのか分かりません。事前に感謝の意を表します!ユーザー定義のcmp関数を使用したPythonソート関数

mydict = { 'a1': (1,6), 
      'a2': (10,2), 
      'a3': (5,3), 
      'a4': (1,2), 
      'a5': (3,9), 
      'a6': (9,7) } 

# sort by first element of the value tuple: WORKS 
print sorted(mydict.iteritems(), key=lambda (k,v): v[0]) 

# sort by second element of the value tuple: WORKS 
print sorted(mydict.iteritems(), key=lambda (k,v): v[1]) 

# THIS is what I can't get working: 
def cmpRatio(x,y): 
    sx = float(x[0])/x[1] 
    sy = float(y[0])/y[1] 
    return sx < sy 

# sort by sum of the elements in the value tuple: DOES NOT WORK 
print sorted(mydict.iteritems(), key=lambda (k,v): v, cmp=cmpRatio) 
+0

を行う私は2つの混乱、合計および比率について謝罪エディタ –

答えて

6

cmpは遅いため、可能な限り機能しません。それぞれの比較のために再評価する必要があります。 keyを使用すると、鍵は1回だけ計算する必要があります。

print sorted(mydict.iteritems(), key=lambda (k,v): float(v[0])/v[1]) 

また、値の項目の合計でソートしたいが、その差でソートしているとします。合計は次のようになります。他の回答で述べたように

print sorted(mydict.iteritems(), key=lambda (k,v): sum(v)) 

、本当にcmp関数を定義したいの目的のために、あなたは(-1,0、または1でなければなりません)、適切な値を返すされていません。

return cmp(sx,sy) 

しかし、また、あなただけの値を取得するためにラムダを使用している場合は、あなたのpython側の機能よりも高速であるべきであるitemgetterとそれを置き換えることができます。

from operator import itemgetter 

print sorted(mydict.iteritems(), key=itemgetter(1), cmp=cmpRatio) 

あなたがしようとしている場合

key_ops = { 
    'sum': lambda (k,v): sum(v), 
    'ratio': lambda (k,v): float(v[0])/v[1]), 
} 

def print_op(aDict, opName): 
    print sorted(aDict.iteritems(), key=key_ops[opName]) 

... # some place later in code 
print_op(mydict, 'sum') 
+0

にはほとんど '{}'ボックスを使用してコードをフォーマットしてみてください私が使用したい様々なコンパレータ関数のうちのどれかです。あなたのソリューションは完璧に機能しますが、私の例は遅いだけでなく、単に機能しないし、私が間違っていることを理解したいと思っています。私は、コンパレータ関数を定義し、それらを他の最適化関数のパラメータとして使用できるようにしたい、つまりそれがcmpを使用しようとしている根本的な理由です。ありがとう! –

+0

@RuxandraPalmtag:なぜあなたは 'cmp'関数が必要なのか分かりません。代わりに、キーに対して複数の 'lambda'操作を定義する必要があります。しかし、あなたの 'cmp'機能に関して更新しました。 – jdi

+0

ああ、私はそれを得る:戻り値、私はそれについて読んだが、登録しなかった:)効率的なコメントありがとう、私はラムダでキーを使用してみて、私のコードで動作する方法を参照してください! –

2

あなたは(あなたのコメントに応じて)値タプルの和でソートしたい場合は、あなたが使用できます。

print sorted(mydict.iteritems(), key=lambda v: sum(v[1])) 

あなたは比率でソートしたい場合は(あなたのコードに応じて):

print sorted(mydict.iteritems(), key=lambda v: float(v[1][0])/v[1][1]) 
4

比較関数は、最初の引数が負の場合は(負の値/ゼロ/正の値)を返す必要があります。 entは(C++のstd::sort(...)に与えられた比較器とは異なり)(第2の値より小さい/等しい/大きい)。

すなわち代わりに

return sx < sy 

return cmp(sx,sy) 
関連する問題