6

現在、次のリストを並べ替えようとしています。

list_ = [(1, '0101'), (1, '1010'), (1, '101'), (2, '01'), (2, '010'), (2, '10')]

これらは、並べ替えるために実行したい手順です。

  1. タプルの最初の要素の値でリストをソートします
  2. 次に、ステップ 1 が終了した後、タプルの 2 番目の要素の長さ(値ではなく、長さです!) でリストを並べ替えます。
  3. 次に、手順 1 と手順 2 が終了した後に、タプルの 2 番目の要素の値でリストを並べ替えます。

私の試み:

sorted_by_length = sorted(list_, key=len x:x[1])

しかし、xafterに関する構文エラーを受け取りましたkey= len。この場合、使用すべき正しい変数は何ですか?

ソートされた正しいリストは次のようになります。

sorted_by_length = [(1, '101'), (1, '0101'), (1, '1010'), (2, '01'), (2, '10'), (2, '010')]

ご協力ありがとう御座います。

4

3 に答える 3

20

キー関数はタプルを返すことができます。

sorted_by_length = sorted(list_,
                         key=lambda x: (x[0], len(x[1]), float(x[1])))

これが機能するのは、タプルが辞書式にソートされるためです: (タプルの最初の要素が最初のソートに使用され、次に 2 番目の要素が同順位の解消に使用され、次に 3 番目の要素が残りの同順位の解消に使用されます。)

これとソートに関連するその他の問題の説明については、優れたHOWTO Sortを参照してください。


In [1]: list_ = [(1, '0101'), (1, '1010'), (1, '101'), (2, '01'), (2, '010'), (2, '10')]

In [2]: sorted_by_length = sorted(list_,
                         key=lambda x: (x[0], len(x[1]), float(x[1])))
   ...: 
In [3]: sorted_by_length
Out[3]: [(1, '101'), (1, '0101'), (1, '1010'), (2, '01'), (2, '10'), (2, '010')]

各タプルの 2 番目の要素がintバイナリの an の文字列表現である場合は、ソート キーのint(x, 2)代わりに使用します。float(x)整数の 10 進数表現を意図している場合は、 を使用しますint(x)

于 2013-10-28T19:10:41.517 に答える
4

コレクションを結果として返すキー関数を使用してソートできます

list_.sort(key=lambda x: [x[0], len(x[1]), x[1]])

keyパラメータを使用して、比較を行う前に各リスト要素で呼び出される関数を指定します。

コレクションをkey結果として使用する場合、最初の要素が等しい場合は最初の要素を比較してソートされ、次に秒の要素が比較されます...

PS私が理解しているように、3番目の項目を数値型にキャストする必要はありません。これは、等しい場合、バイナリ値の辞書式順序と数値順序で同じ結果が得られるためです。

于 2013-10-28T19:14:32.020 に答える
2

正しい解決策はkey、unutbu の回答に示されているように、タプルを返す関数を使用することです。ただし、別の方法があります。Python のソートは安定していることが保証されているため、異なるキーで複数のソートを実行して、必要な出力を得ることができます。特に:

list_.sort(key=lambda x: float(x[1]))
list_.sort(key=lambda x: len(x[1]))
list_.sort(key=lambda x: x[0])

IPython を使用したデモ:

In [1]: list_ = [(1, '0101'), (1, '1010'), (1, '101'), (2, '01'), (2, '010'), (2, '10')]

In [2]: list_.sort(key=lambda x: float(x[1]))
   ...: list_.sort(key=lambda x: len(x[1]))
   ...: list_.sort(key=lambda x: x[0])
   ...: 

In [3]: list_
Out[3]: [(1, '101'), (1, '0101'), (1, '1010'), (2, '01'), (2, '10'), (2, '010')]

: この解決策は、質問で説明した 3 つの手順に似ています、手順が逆になっています。正しい出力を得るには、主キーの最後で並べ替えます。

また、ソートに使用されるアルゴリズムは適応型であることにも注意してください。これは、シーケンスがすでに部分的にソートされている場合、部分的な順序を使用してより効率的にソートできることを意味します (多くの場合、ではなく線形時間でnlog(n))。複数のキーで並べ替えると、多くの場合、この部分的な順序が達成されるため、複数回呼び出してsort()もそれほどコストはかかりません。ただし、キーとデータに大きく依存します。タプルをキーとして使用するよりも効率的な場合もあれば、非常に遅い場合もあります。


タイミングの一例。2 つのソリューションには、ほとんど同じ時間がかかることに注意してください。

In [9]: list_
Out[9]: [(1, '0101'), (1, '1010'), (1, '101'), (2, '01'), (2, '010'), (2, '10')]

In [10]: list_ *= 1000   # better to avoid too small benchmarks.

In [11]: %%timeit
    ...: a = sorted(list_, key=lambda x: (x[0], len(x[1]), float(x[1])))
    ...: 
100 loops, best of 3: 6.04 ms per loop

In [12]: %%timeit
    ...: a = sorted(list_, key=lambda x: float(x[1]))
    ...: a.sort(key=lambda x: len(x[1]))
    ...: a.sort(key=lambda x: x[0])
    ...: 
100 loops, best of 3: 5.72 ms per loop
In [13]: import random
    ...: data = [(random.randint(1, 1000), bin(random.randint(1, 100))[2:]) for _ in range(10000)]
    ...: 

In [14]: %%timeit
    ...: a = sorted(data, key=lambda x: (x[0], len(x[1]), float(x[1])))
    ...: 
100 loops, best of 3: 15.2 ms per loop

In [15]: %%timeit
    ...: a = sorted(data, key=lambda x: float(x[1]))
    ...: a.sort(key=lambda x: len(x[1]))
    ...: a.sort(key=lambda x: x[0])
    ...: 
100 loops, best of 3: 15.1 ms per loop
于 2013-10-28T20:09:25.690 に答える