Pythonリストを2つのフィールドでソートする


173

ソートされたcsvから次のリストを作成しました

list1 = sorted(csv1, key=operator.itemgetter(1))

最初にフィールド1の値で、次にフィールド2の値で、2つの基準でリストを実際にソートしたいと思います。これを行う方法を教えてください。



私たちは、この質問が立つだけに、その範囲を制限できます「リスト・オブ・リスト-の長-2-組み込み-型(例えば文字列/ INT /フロート)」。または、タイトルが示唆しているように、「ユーザー定義オブジェクトのリスト」も許可しますか。その場合、答えは__lt__()クラスのメソッドを定義するか、そうするクラスから継承する」です。それはそれをはるかに良い正規化するでしょう。
smci

回答:


158

このような:

import operator
list1 = sorted(csv1, key=operator.itemgetter(1, 2))

1
+1:私よりエレガント。itemgetterは複数のインデックスを取ることができることを忘れていました。
dappawit

7
operatorインポートする必要があるモジュールです。
trapicki 2013

3
itemgetterを使用して、1つの要素を昇順で並べ替え、他の要素を降順で並べ替える場合はどうすればよいですか?
ashish 2013年

3
@ashish、ラムダ関数を使用して以下の私の回答を参照してください。これは明確です。希望する場合は「-x [1]」または「x [0] + x [1]」で並べ替えます
jaap

逆モードの1つの基準の場合はどうですか?
YaserKH 2018年

328

ラムダ関数を使用するときに何もインポートする必要はありません。
次の例でlistは、最初の要素、2番目の要素の順に並べ替えます。

sorted(list, key=lambda x: (x[0], -x[1]))

12
いいね。上記の主な回答へのコメントで述べたように、これは異なる並べ替え順序で複数の並べ替えを行うための最良の(唯一の?)方法です。おそらくそれを強調します。また、テキストは、2番目の要素で降順に並べ替えたことを示していません。
PeterVermont

2
@ user1700890フィールドはすでに文字列であると想定していました。デフォルトでは、文字列をアルファベット順にソートする必要があります。ここでの回答またはOPの元の質問に特に関連しない場合は、SOに独自の質問を個別に投稿する必要があります。
聖書2015年

5
-in は何の-x[1]略ですか?
2016

7
@jan逆ソート
jaap

3
特定のケースでは機能しません。承認されたソリューションも機能しません。たとえば、キーとして使用される列はすべて、数値に変換できない文字列です。次に、1つの列で昇順、別の列で降順で並べ替えたい場合です。
coder.in.me 2016

20

Pythonは安定したソートを備えているため、パフォーマンスが問題にならない限り、フィールド2でソートしてからフィールド1で再度ソートするのが最も簡単な方法です。

それはあなたにあなたが望む結果を与えるでしょう、唯一のキャッチはそれが大きなリストであるなら(またはあなたがそれを頻繁にソートしたいなら)sortを2回呼び出すことは許容できないオーバーヘッドになるかもしれないということです。

list1 = sorted(csv1, key=operator.itemgetter(2))
list1 = sorted(list1, key=operator.itemgetter(1))

このようにすることで、一部の列を逆に並べ替えたい場合の処理​​も簡単になり、必要に応じて 'reverse = True'パラメータを含めるだけです。

それ以外の場合は、itemgetterに複数のパラメーターを渡すか、手動でタプルを作成できます。それはおそらくより高速になりますが、一部の列を逆ソートしたい場合、一般化がうまくいかないという問題があります(数値列は否定することによって逆にすることはできますが、ソートが安定しなくなります)。

したがって、列を逆に並べ替える必要がない場合は、itemgetterに複数の引数を使用します。可能であれば、列が数値でないか、並べ替えを安定した状態に保ち、複数の連続した並べ替えを行います。

編集:これが元の質問にどのように答えるかを理解するのに問題があるコメンターのために、これはソートの安定した性質がどのように各キーで個別のソートを実行し、複数の基準でソートされたデータになるかを正確に示す例です:

DATA = [
    ('Jones', 'Jane', 58),
    ('Smith', 'Anne', 30),
    ('Jones', 'Fred', 30),
    ('Smith', 'John', 60),
    ('Smith', 'Fred', 30),
    ('Jones', 'Anne', 30),
    ('Smith', 'Jane', 58),
    ('Smith', 'Twin2', 3),
    ('Jones', 'John', 60),
    ('Smith', 'Twin1', 3),
    ('Jones', 'Twin1', 3),
    ('Jones', 'Twin2', 3)
]

# Sort by Surname, Age DESCENDING, Firstname
print("Initial data in random order")
for d in DATA:
    print("{:10s} {:10s} {}".format(*d))

print('''
First we sort by first name, after this pass all
Twin1 come before Twin2 and Anne comes before Fred''')
DATA.sort(key=lambda row: row[1])

for d in DATA:
    print("{:10s} {:10s} {}".format(*d))

print('''
Second pass: sort by age in descending order.
Note that after this pass rows are sorted by age but
Twin1/Twin2 and Anne/Fred pairs are still in correct
firstname order.''')
DATA.sort(key=lambda row: row[2], reverse=True)
for d in DATA:
    print("{:10s} {:10s} {}".format(*d))

print('''
Final pass sorts the Jones from the Smiths.
Within each family members are sorted by age but equal
age members are sorted by first name.
''')
DATA.sort(key=lambda row: row[0])
for d in DATA:
    print("{:10s} {:10s} {}".format(*d))

これは実行可能な例ですが、実行している人を救うための出力は次のとおりです。

Initial data in random order
Jones      Jane       58
Smith      Anne       30
Jones      Fred       30
Smith      John       60
Smith      Fred       30
Jones      Anne       30
Smith      Jane       58
Smith      Twin2      3
Jones      John       60
Smith      Twin1      3
Jones      Twin1      3
Jones      Twin2      3

First we sort by first name, after this pass all
Twin1 come before Twin2 and Anne comes before Fred
Smith      Anne       30
Jones      Anne       30
Jones      Fred       30
Smith      Fred       30
Jones      Jane       58
Smith      Jane       58
Smith      John       60
Jones      John       60
Smith      Twin1      3
Jones      Twin1      3
Smith      Twin2      3
Jones      Twin2      3

Second pass: sort by age in descending order.
Note that after this pass rows are sorted by age but
Twin1/Twin2 and Anne/Fred pairs are still in correct
firstname order.
Smith      John       60
Jones      John       60
Jones      Jane       58
Smith      Jane       58
Smith      Anne       30
Jones      Anne       30
Jones      Fred       30
Smith      Fred       30
Smith      Twin1      3
Jones      Twin1      3
Smith      Twin2      3
Jones      Twin2      3

Final pass sorts the Jones from the Smiths.
Within each family members are sorted by age but equal
age members are sorted by first name.

Jones      John       60
Jones      Jane       58
Jones      Anne       30
Jones      Fred       30
Jones      Twin1      3
Jones      Twin2      3
Smith      John       60
Smith      Jane       58
Smith      Anne       30
Smith      Fred       30
Smith      Twin1      3
Smith      Twin2      3

特に、2番目のステップでreverse=Trueパラメーターが最初の名前を順番に保持する方法に注意してください。一方、単に並べ替えてからリストを逆にすると、3番目の並べ替えキーの目的の順序が失われます。


1
安定したソートは、以前のソートが何であったかを忘れないという意味ではありません。この答えは間違っています。
Mike Axiak

7
安定したソートとは、列c、b、aの順にソートするだけで、列a、b、cでソートできることを意味します。あなたがあなたのコメントを拡大することを気にしない限り、私はあなたが間違っていると思います。
ダンカン

7
この答えは間違いなく正しいですが、リストが大きい場合は理想的ではありません。リストがすでに部分的にソートされている場合は、リストをより多くシャッフルすることにより、Pythonのソートの最適化の大部分が失われます。@マイク、あなたは間違っています。答えを間違っていると宣言する前に、実際にテストすることをお勧めします。
Glenn Maynard

6
@MikeAxiak:docs.python.org/2/library/stdtypes.html#index-29コメントの状態9:Python 2.3以降、sort()メソッドは安定していることが保証されています。等しいと比較する要素の相対的な順序を変更しないことが保証されている場合、並べ替えは安定しています。これは、複数のパスで並べ替える場合に便利です(たとえば、部門で並べ替えてから、給与等級で並べ替えます)。
trapicki 2013

これは彼が尋ねた質問に答えないので、これは正しくありません。彼は最初のインデックスでソートされたリストを望んでおり、最初のインデックスにタイがある場合は、ソート基準として2番目のインデックスを使用したいと考えています。安定したソートは、すべてのものが等しいことを保証するだけです。渡された元の順序は、アイテムが表示される順序になります。
Jon

14
list1 = sorted(csv1, key=lambda x: (x[1], x[2]) )

4
私はtuple()2つの引数を受け取ることができるとは思いません(または、で数えると3つself
フィリペコレイア

3
タプルは、引数を1つしか取ることができません
therealprashant

1
returnステートメントは、return tuple((x[1], x[2]))または単にする必要がありますreturn x[1], x[2]。 別の方向でのソートをお探しの場合は、@ jaapの回答を参照してください
Jo Kachikaran

…またはtuple(x[1:3])、タプルディスプレイリストだけでなく、何らかの理由でタプルコンストラクタを使用する場合x[1], x[2]。またはkeyfunc = operator.itemgetter(1, 2)、関数を自分で作成しないでください。
abarnert

3
employees.sort(key = lambda x:x[1])
employees.sort(key = lambda x:x[0])

python sortが適切で安定しているため、.sortをlambdaで2回使用することもできます。これは最初に、2番目の要素x [1]に従ってリストをソートします。次に、最初の要素x [0](最高優先度)をソートします。

employees[0] = Employee's Name
employees[1] = Employee's Salary

これは、以下を実行することと同等です。employees.sort(key = lambda x:(x [0]、x [1]))


1
いいえ、この並べ替えルールは2番目に優先する必要があります。
CodeFarmer

1

昇順で使用できます。

sorted_data= sorted(non_sorted_data, key=lambda k: (k[1],k[0]))

または降順で使用できます:

sorted_data= sorted(non_sorted_data, key=lambda k: (k[1],k[0]),reverse=True)

0

以下を使用して辞書のリストを並べ替えると、最初の列が給与として、2番目の列が年齢として降順にリストが並べ替えられます

d=[{'salary':123,'age':23},{'salary':123,'age':25}]
d=sorted(d, key=lambda i: (i['salary'], i['age']),reverse=True)

出力:[{'salary':123、 'age':25}、{'salary':123、 'age':23}]

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