10

次の辞書の Python 配列があります。

myarr = [ { 'name': 'Richard', 'rank': 1 },
{ 'name': 'Reuben', 'rank': 4 },
{ 'name': 'Reece', 'rank': 0 },
{ 'name': 'Rohan', 'rank': 3 },
{ 'name': 'Ralph', 'rank': 2 },
{ 'name': 'Raphael', 'rank': 0 },
{ 'name': 'Robin', 'rank': 0 } ]

次のようにランク値で並べ替えたいと思います: 1-2-3-4-0-0-0。

私が試してみると:

sorted_master_list = sorted(myarr, key=itemgetter('rank'))

次に、リストは 0-0-0-1-2-3-4 の順序でソートされます。

リストの最後にゼロをプッシュするカスタム コンパレータ関数を定義するにはどうすればよいですか? methodcallerのようなものを使用できるかどうか疑問に思っています。

4

8 に答える 8

23

オプション1:

key=lambda d:(d['rank']==0, d['rank'])

オプション 2:

key=lambda d:d['rank'] if d['rank']!=0 else float('inf')

デモ:

「1-2-3-4-0-0-0 のようにランク値で並べ替えたいと思います。」--オリジナルポスター

>>> sorted([0,0,0,1,2,3,4], key=lambda x:(x==0, x))
[1, 2, 3, 4, 0, 0]

>>> sorted([0,0,0,1,2,3,4], key=lambda x:x if x!=0 else float('inf'))
[1, 2, 3, 4, 0, 0]

 

追加コメント:

「私 (Python の初心者) に、それが何をしているのか説明していただけますか? これはラムダ関数であることがわかります。これは無名関数であることがわかっています。括弧内のビットは何ですか?」・OPコメント

索引付け/スライス表記:

itemgetter('rank')関数と同じlambda x: x['rank']ものです:

def getRank(myDict):
    return myDict['rank']

[...]はインデックス作成/スライス表記と呼ばれます。Python のスライス表記についての説明を参照してください。これsomeArray[n]は、多くのプログラミング言語でインデックス作成に使用される一般的な表記ですが、[start:end]またはの形式のスライスはサポートされない場合があることにも注意してください[start:end:step]

key=vs cmp=vs リッチ比較:

何が起こっているかについては、ソートアルゴリズムがどのようにkey機能するかを指定する一般的な方法が 2 つありますcmp。関数を使用すると、cmp2 つの要素を比較する方法を任意に指定できます (入力: a, b; 出力:a<bまたはa>bまたはa==b)。正当ではありますが、大きなメリットはありません (厄介な方法でコードを複製する必要があります)。cmp=(洗練された、しかしおそらく過剰な方法で暗黙的に定義する方法については、「オブジェクトの豊富な比較」を参照してください。)

キー機能の実装:

残念ながら、0 は整数の要素であるため、自然な順序付けがあります。通常、0 は < 1,2,3 です... したがって、追加のルールを課したい場合は、リストを「上位レベル」でソートする必要があります。キーをタプルにすることでこれを行います: タプルは最初に最初の要素でソートされ、次に 2 番目の要素でソートされます。True は常に False の後に並べられるため、すべての True は Falses の後に並べられます。その後、通常どおりにソートされます: (True,1)<(True,2)<(True,3)<...(False,1)<(False,2)<...(False,*)<(True,*). 別の方法 (オプション 2) は、ランク 0 の辞書に無限大の値を割り当てるだけです。

より一般的な代替手段- オブジェクトの豊富な比較:

さらに一般的な解決策は、レコードを表すクラスを作成してから__lt____gt____eq____ne____gt____ge__およびその他すべての豊富な比較演算子を実装するか、それらのいずれかを実装してデコレータ__eq__を使用することです。これにより、比較演算子 ( など)を使用するたびに、そのクラスのオブジェクトがカスタム ロジックを使用するようになります。関数は比較ソートでデフォルトで and 他の比較演算子を使用するため、これにより、ソート時の動作が自動化され、および 他の比較演算子を使用する他のインスタンスで動作が自動化されます。これは、ユースケースに応じて、過剰になる場合とそうでない場合があります。@functools.total_orderingx=Record(name='Joe', rank=12) y=Record(...) x<ysorted(...)<<

よりクリーンな代替手段- セマンティクスで 0 をオーバーロードしないでください:

ただし、1、2、3、4 などの後ろに 0 を置くのは少し人工的であることを指摘しておく必要があります。これが正当化されるかどうかは、rank=0 が本当に rank=0 を意味するかどうかに依存します。ランク= 0がランク= 1よりも実際に「低い」場合(ランク= 2よりも実際に「低い」...)。これが本当に当てはまる場合、あなたの方法はまったく問題ありません。そうでない場合は、'rank':...を設定するのではなく、エントリを省略することを検討してください'rank':0。次に、を使用して Lev Levitsky の回答'rank' in dで並べ替えるか、次の方法で並べ替えることができます。

別のスキームのオプション 1:

key=lambda d: (not 'rank' in d, d['rank'])

別のスキームのオプション 2:

key=lambda d: d.get('rank', float('inf'))

補足: Python での無限の存在に依存することは、ほぼ境界線上にあるハックであり、前述のソリューション (タプル、オブジェクト比較)、Lev のfilter-then-concatenate ソリューション、さらには少し複雑なcmpソリューション(タイプアップ) のいずれかを作成します。ウィルソンによる)、他の言語へのより一般化が可能です。

于 2012-04-12T18:34:07.603 に答える
1

具体的には「0」を処理するための比較関数を作成することに傾倒しています。

def compare(x,y):
    if x == y:
        return 0
    elif x == 0:
        return 1
    elif y == 0:
        return -1
    else:
        return cmp(x,y)

sorted(myarr, cmp=lambda x,y: compare(x,y), key=lambda x:x['rank'])

ただし、カスタム比較関数ではパフォーマンスが低下します。

于 2012-04-12T19:13:38.643 に答える
1

私はするだろう

 sortedlist = sorted([x for x in myarr if x['rank']], key=lambda x: x['rank']) + [x for x in myarr if not x['rank']]

どうにかして圧縮できると思います。

于 2012-04-12T18:38:41.253 に答える
-1

それを行うハックな方法は次のとおりです。

sorted_master_list = sorted(myarr, key=lambda x: 99999 if x['rank'] == 0 else x['rank'])

これは、自分の最大ランクがわかっている場合はかなりうまく機能します。

于 2012-04-12T18:34:09.383 に答える
-1

ここmyarrでバインドしているのが、有効な Python コードのようには見えません (そして、私のインタープリター セッションでは実行されません。

それを次のようにレンダリングします。

myarr = {
    'Richard': 1,
    'Reuben': 4,
    'Reece': 0,
    'Rohan': 3,
    'Ralph': 2,
    'Raphael': 0,
    'Robin': 0 }

答えの基礎となる何かを教えてくれます。

Python でカスタムの並べ替えを行うには、DSU (装飾、並べ替え、装飾解除) パターンを使用することをお勧めします。ディクショナリを値でソートする場合は、次のようになります。

keys_sorted_by_val = [ x[1] for x in sorted([(v,k) for k,v in myarr.items()])]

...装飾(v,k) for k,v in myarr.items()する式はどこにありますか; 明らかに、並べ替えであり、外側は装飾を解除する最後のステップです。sorted()x[1] for x in ...

明らかに、これは十分に一般的な要件のように思えるかもしれませんが、これを関数でラップする必要があります。

def dict_by_values(d):
    return [ x[1] for x in sorted([(v,k) for k,v in d.items()])]

何らかの属性でソートしたいオブジェクト インスタンスのコレクションがある場合は、次のようなものを使用できます。

def sort_by_attr(attr, coll):
    results = list()
    for each in coll:
        assert hasattr(each, attr)
        results.append((getattr(each, attr), each))
    results.sort()
    return [x[1] for x in results]

したがって、次のような名前/ランク データを表すクラスを作成したとします。

class NameRanking(object):
    def __init__(self, name, rank):
        self.name = name
        self.rank = rank
    def __repr__(self):
        return "%s: %s, %s" %(self.__class__, self.name, self.rank)

...そして、以下を使用してそれらのリストをインスタンス化しますmyarr:

name_rankings = [ myarr.items() の k,v に対する NameRanking(k, v) ]

...次に、次を使用してそのソートされたコピーを取得できます。

names_rankings_by_rank = sort_by_attr('rank', name_rankings)

(はい、assertここでは良い考えではありません。アプリケーションに応じて、独自の例外処理またはスロー コードを配置する場所です)。

于 2012-04-12T19:30:26.097 に答える
-2

「キー」に任意の関数または呼び出し可能なオブジェクトを渡すだけです-それが必要です。itemgetterたまたまそのような関数の 1 つですが、それはあなたが作成した任意の関数で動作します。単一のパラメーターを入力として取り、必要な順序を達成するために直接互換性のあるオブジェクトを返すだけです。

この場合:

def key_func(item):
   return item["rank"] if item["rank"] != 0 else -100000

sorted_master_list = sorted(myarr, key=key_func)

(ラムダ式でも書けます)

于 2012-04-12T18:33:52.847 に答える
-3

キーパラメータで関数を使用できます:

お尻の選別用:

sorted_master_list = sorted(myarr, key=lambda x: x.get('rank'))

または降順:

sorted_master_list = sorted(myarr, key=lambda x: -x.get('rank'))

また、ここでソートされた関数について読むことができますhttp://wiki.python.org/moin/HowTo/Sorting

于 2012-04-12T18:34:02.867 に答える
-3

sorted_master_list = sorted(myarr, key=itemgetter('rank'), reverse=True) を試してください

于 2012-04-12T18:36:15.987 に答える