Pythonのリストを効率よくソート(並び替え)する方法を解説します。昇順、降順、逆順を全て把握することができますので、ぜひ参考にして頂ければと思います。
1. sort()メソッド
リストはsort()メソッドでソートすることができます。次のように書きます。
リスト.sort()
このsort()メソッドは、要素をソートした新しいリストを作るのではなく、元のリストの要素を並び替えます。
括弧 () の中に書く値を「引数(ひきすう)」と言いますが、引数によってさまざまなソートの基準を指定することができます。
それでは使い方を実際に見てみましょう。
1.1. 昇順でソート
sort()メソッドの引数を空白にした場合は、次の条件でソートします。
- 数値昇順
- アルファベット昇順
- あいうえお・アイウエオ昇順
- 文字が混在する場合はユニコード順(アルファベット→かな→カナ順)
いくつか例を見てみましょう。
以下のコードでは数値を昇順でソートしています。
nums = [3, 5, 2, 4, 1]
nums.sort()
print(nums)
なお、あくまでも元のリストをソートするので、メソッド自体の返り値はNoneです。以下のように、メソッドの実行結果そのものを出力しないようにしましょう。
nums = [3, 5, 2, 4, 1]
print(nums.sort())
英語文字はアルファベット順でソートします。
letters = ['e', 'b', 'a', 'c', 'd']
letters.sort()
print(letters)
アルファベットで大文字と小文字が混在するリストの場合は、まず大文字、次に小文字の順で昇順でソートします。
alphabets = ['E', 'b', 'a', 'C', 'd']
alphabets.sort()
print(alphabets)
一つのリストに複数種類の文字が混在する場合は、「大文字アルファベット→小文字アルファベット→ひらがな→カタカナ」の順でソートします。
mixed = ['あ', 'ア', 'a', 'A']
mixed.sort()
print(mixed)
なお、数値と文字列が混在しているリストにsort()メソッドを使うとエラーになります。
# 数値と文字列が混在しているリストではソート不可
numletters = [1, 'あ', 'ア', 'a', 'A']
numletters.sort()
print(numletters)
1.2. 降順でソート
降順でソートするには、メソッドの引数に「reverse=True」と書きます。
nums = [3, 5, 2, 1, 4]
nums.sort(reverse=True)
print(nums)
letters = ['a', 'c', 'd', 'b', 'e']
letters.sort(reverse=True)
print(letters)
1.3. keyを指定して任意の条件でソート
sortメソッドの引数に、「key=○○○」と書くと様々な基準でソートします。
例えば、大文字と小文字の区別なくソートするには、メソッドの引数に「key=str.lower」と書きます。
alphabets = ['E', 'b', 'a', 'C', 'd']
alphabets.sort(key=str.lower)
print(alphabets)
「key=len」と書くと長さ順にソートします。
words = ['aaaaa', 'bbb', 'c', 'dd', 'eeee']
words.sort(key=len)
print(words)
なお、引数の「reverse」と「key」は両立することができます。
words = ['aaaaa', 'bbb', 'c', 'dd', 'eeee']
words.sort(reverse=True, key=len)
print(words)
「key=str.lower」 や「key=len」に見られるように、sort()メソッドの引数に渡す「key=」の右辺にはメソッドや関数を書いています。str.lower()は文字列を小文字に変換するメソッドですし、len()はオブジェクトの長さを返す関数です。
つまり、sort()メソッドは、「key=」で設定したメソッドや関数の機能の通りにソートするのです。
このことから、メソッドや関数を自作することで、ソート条件を自作することができます。例えば、sort()メソッドは多重リストをソートする場合、内側のリストの最初(インデックス番号0番)の要素を基準に並び替えます。
list = [[0, 2], [1, 1], [2, 0]]
list.sort()
print(list)
もし、内側のリストの2つ目(インデックス番号1番)を基準にソートしたい場合は、次のようにlambda式やdef文で、インデックス番号1番の要素を参照する関数を作り、それをsort()メソッドの「key=」の右辺に渡します。
sortsecond = lambda val: val[1]
list = [[0, 2], [1, 1], [2, 0]]
list.sort(key=sortsecond)
print(list)
結果、内側のリストのインデックス番号1番の値を基準にソートされました。
なお、def文に関しては「Pythonのdef文を使った関数の作り方」、lambdaについては「Pythonのlambda(ラムダ式)の書き方」をご覧ください。
2. sorted()関数
sorted()関数は、sort()メソッドと使い方は全く同じですが、元のリストの要素をソートするのではなく、要素をソートした新しいリストを作る点が異なります。
また関数なので、次のように書きます。
sorted(リスト)
使い方を実際に見てみましょう。
2.1. 昇順でソート
関数の引数にリストだけを渡すと、sort()メソッドと全く同じルールで昇順でソートします。
nums = [3, 5, 2, 4, 1]
print(sorted(nums))
sort()メソッドと違って、要素をソートした新しいリストを作るので、それを別の変数に代入して出力することもできます。
letters = ['e', 'b', 'a', 'c', 'd']
ls_ordered = sorted(letters)
print(ls_ordered)
2.2. 降順でソート
sorted()関数で降順でソートしたい場合は、第二引数に「reverse=True」と書きます。
nums = [3, 5, 2, 1, 4]
print(sorted(nums, reverse=True))
letters = ['a', 'c', 'd', 'b', 'e']
print(sorted(letters, reverse=True))
2.3. keyを指定して任意の条件でソート
sort()メソッドと同じく、第二引数以降で、「key=○○○」と書くことでソートの条件を指定することができます。「reverse=True」との併用も可能です。
alphabets = ['E', 'b', 'a', 'C', 'd']
# 大文字小文字の区別なくソート
print(sorted(alphabets, key=str.lower))
words = ['aaaaa', 'bbb', 'c', 'dd', 'eeee']
# 長さ順にソート
print(sorted(words, key=len))
# 長さ逆順にソート
print(sorted(words, reverse=True, key=len))
lambda式やdef文で、関数やメソッドを自作できるようになると、任意の条件でソートできるようになります。
list = [[0, 2], [1, 1], [2, 0]]
sortsecond = lambda val : val[1]
print(sorted(list))
print(sorted(list, key=sortsecond))
def文に関しては「Pythonのdef文を使った関数の作り方」、lambdaについては「Pythonのlambda(ラムダ式)の書き方」をご覧ください。
3. reverse()メソッドで逆順ソート
reverse()メソッドを使うと、元のリストを逆順でソートします。関数のようにソートした新しいリストを作るのではありませんので注意しましょう。次のように書きます。
リスト.reverse()
実際に見てみましょう。
nums = [3, 5, 2, 4, 1]
nums.reverse()
print(nums)
letters = ['e', 'b', 'a', 'c', 'd']
letters.reverse()
print(letters)
それぞれ既存のリストを逆順にソートしています。
sort()メソッドと同じように、元のリストを逆順でソートするので、メソッドの返り値自体はNoneです。関数と同じような使い方はできないので注意しましょう。
nums = [3, 5, 2, 4, 1]
print(nums.reverse())
なおsort()メソッドとsorted()関数があるように、reversed()関数というものもあります。これはsorted()関数のように新しいリストを作るのではなく、イテレータ型オブジェクトを作ります。
イテレーターはfor文による要素の取り出しなどで使います。「Pythonのfor文による繰り返し処理(forループ)の基本」で確認しておくと良いでしょう。
さらに、リストのスライスによっても逆順並び替えは可能です(「Pythonのリストのスライスと分割」をご確認ください)。
nums[::-1]
この方法の場合は、以下のように別の変数に代入して新しいリストを作ることができます。
r_nums = nums[::-1]
print(r_nums)
reverse()メソッドを使った方法とスライスを使った方法で、それぞれ10万回試行した時のソートの平均速度は次の通りです。
- reverse()メソッド:平均117ナノ秒(標準偏差23ナノ秒)
- スライス:平均179ナノ秒(標準偏差23.6ナノ秒)
reverse()メソッドの方がかなり早いので、逆順にしたい場合はそちらを使う方が良いでしょう。
4. まとめ
リストのソートについては、sort()メソッドとsorted()関数の使い方をしっかりとマスターしておきましょう。sort()メソッドは元のリストをソートします。sorted()関数は、要素をソートした新しいリストを作ります。この点から、前者は「非破壊的ソート」、後者は「破壊的ソート」とも言われます。
両方とも書き方は同じで、逆順でソートしたい時は引数に「reverse=True」と書きます。さらに、「key=○○○」でソートの基準を任意で指定することもできます。def文やlambda式で関数を定義できるようになると、さらに幅が広がります。
また、現在のリストを、そのまま逆順にしたい場合はreverse()メソッドを使います。要素を逆順にした新しいリストを作りたい場合は、スライスを使う方法があります。
それぞれおさえておきましょう。
コメント