段階的なソートについて説明します。
段階的なソートとは、例えば3行3列の2次元リストがある時に、2列目を基準にソートした後に3列目を基準にソートすることです。
sortedを1回使用する場合と複数回使用する場合がありますが、 sortedを1回使用する場合の方がおすすめです。考え方が直感的であり、コードも短いためです。但し、任意の列を降順にソートする場合は、sortedを複数回使用する必要があります。
段階的なソート
下記、リストを血液型→体重の優先度でソートすることを考えます。優先度が高い列の値が辞書順で先か、小さいほどソート後に上の行になります 。
本章では、リストの列を基準として昇順にソート行うことを前提に説明をします。つまり、ソートすると辞書順で先である文字列、小さい数値ほど上の行になります。
human = [ #名前 , 血液型, 体重 ('tadasi', 'O', 50 ), ('kiyosi', 'O', 100 ), ('masasi', 'A', 70 ), ]
sortedを1回使用する場合
itemgetterを使用
下記により、段階的なソートができます。
sorted(ソート対象のリスト, key=itemgetter(ソートの基準とする列1, ソートの基準とする列 2、…))
優先度が高い列を左から順に、itemgetterの引数として与えてください。
血液型→体重の優先度でソートするため、下記コードでは itemgetter(血液型の列、体重の列)としてソートしています。
from operator import itemgetter human = [ #名前 , 血液型, 体重 ('tadasi', 'O', 50 ), ('kiyosi', 'O', 100 ), ('masasi', 'A', 70 ), ] #正しい例: s1 = sorted(human, key=itemgetter(1, 2)) print(*s1, sep="\n") """出力 ('masasi', 'A', 70) ('tadasi', 'O', 50) ('kiyosi', 'O', 100) """ #誤った例: s2 = sorted(human, key=itemgetter(2, 1)) print(*s2, sep="\n") """出力 ('tadasi', 'O', 50) ('masasi', 'A', 70) ('kiyosi', 'O', 100) """
ラムダ式を使用
ラムダ式を使用した方法を示します。
human = [ #名前 , 血液型, 体重 ('tadasi', 'O', 50 ), ('kiyosi', 'O', 100 ), ('masasi', 'A', 70 ), ] #正しい例: s1 = sorted(human, key=lambda x:(x[1], x[2])) print(*s1, sep="\n") """出力 ('masasi', 'A', 70) ('tadasi', 'O', 50) ('kiyosi', 'O', 100) """
sortedを複数回使用する場合
itemgetterを使用
下記により、段階的なソートができます。
リスト① = sorted(ソート対象のリスト, key=itemgetter(ソートの基準とする列1))
リスト② = sorted(ソート対象のリスト(リスト①), key=itemgetter(ソートの基準とする列 2))
優先度が低い列から順にソートしてください。そうしないと、最終結果が望んだ優先度順でソートされたものになりません。
血液型→体重の優先度でソートしたい場合は、体重を基準としてソートした後に、血液型を基準にソートする必要があります。
from operator import itemgetter human = [ #名前 , 血液型, 体重 ('tadasi', 'O', 50 ), ('kiyosi', 'O', 100 ), ('masasi', 'A', 70 ), ] #正しい例:体重でソート → 血液型でソート s1 = sorted(human, key=itemgetter(2)) print(*s1, sep="\n") """出力 ('tadasi', 'O', 50) ('masasi', 'A', 70) ('kiyosi', 'O', 100) """ s1 = sorted(s1, key=itemgetter(1)) print(*s1, sep="\n") """出力 ('masasi', 'A', 70) ('tadasi', 'O', 50) ('kiyosi', 'O', 100) """ #誤った例:血液型でソート → 体重でソート s2 = sorted(human, key=itemgetter(1)) print(*s2, sep="\n") """出力 ('masasi', 'A', 70) ('tadasi', 'O', 50) ('kiyosi', 'O', 100) """ s2 = sorted(s2, key=itemgetter(2)) print(*s2, sep="\n") """出力 ('tadasi', 'O', 50) ('masasi', 'A', 70) ('kiyosi', 'O', 100) """
ラムダ式を使用
ラムダ式を使用した方法を示します。
human = [ #名前 , 血液型, 体重 ('tadasi', 'O', 50 ), ('kiyosi', 'O', 100 ), ('masasi', 'A', 70 ), ] #正しい例:体重でソート → 血液型でソート s1 = sorted(human, key=lambda x: x[2]) print(*s1, sep="\n") """出力 ('tadasi', 'O', 50) ('masasi', 'A', 70) ('kiyosi', 'O', 100) """ s1 = sorted(s1, key=lambda x: x[1]) print(*s1, sep="\n") """出力 ('masasi', 'A', 70) ('tadasi', 'O', 50) ('kiyosi', 'O', 100) """
降順にソート
2次元リストの任意の列を降順にソートすることを考えます。
「sortedを1回使用する方法」でreverse=Trueとして降順にソートする場合、2次元リストの全ての列が降順にソートされてしまいます。
そのため、2次元リストの任意の列のみを降順にソートする場合は、「sortedを複数回使用する方法」でソートする必要があります。
下記コード( 血液型→体重の優先度でソート)から、 「sortedを1回使用する方法」でreverse=Trueとして降順にソートする場合、2次元リストの全ての列が降順にソートされることがわかります。
from operator import itemgetter human = [ #名前 , 血液型, 体重 ('tadasi', 'O', 50 ), ('kiyosi', 'O', 100 ), ('masasi', 'A', 70 ), ] s1 = sorted(human, key=itemgetter(1, 2), reverse=True) print(*s1, sep="\n") """出力 ('kiyosi', 'O', 100) ('tadasi', 'O', 50) ('masasi', 'A', 70) """
下記コード ( 血液型→体重の優先度でソート) では、 2次元リストの任意の列のみを降順にソートしています。
from operator import itemgetter human = [ #名前 , 血液型, 体重 ('tadasi', 'O', 50 ), ('kiyosi', 'O', 100 ), ('masasi', 'A', 70 ), ] #体重のみ降順にソート s1 = sorted(human, key=itemgetter(2), reverse=True) print(*s1, sep="\n") """出力 ('kiyosi', 'O', 100) ('tadasi', 'O', 50) ('masasi', 'A', 70) """ s1 = sorted(s1, key=itemgetter(1)) print(*s1, sep="\n") """出力 ('masasi', 'A', 70) ('kiyosi', 'O', 100) ('tadasi', 'O', 50) """ #血液型のみ降順にソート s1 = sorted(human, key=itemgetter(2)) print(*s1, sep="\n") """出力 ('tadasi', 'O', 50) ('masasi', 'A', 70) ('kiyosi', 'O', 100) """ s1 = sorted(s1, key=itemgetter(1), reverse=True) print(*s1, sep="\n") """出力 ('tadasi', 'O', 50) ('kiyosi', 'O', 100) ('masasi', 'A', 70) """
参考
ソート HOW TO — Python 3.9.4 ドキュメント
ソートの安定性と複合的なソート
Complex sort with multiple parameters?
ラムダ式を使用した方法
コメント