[Python] リストのソートまとめ(クラス、複数キー、降順、破壊的ソート)

[Python] リストのソートまとめ(クラス、複数キー、降順、破壊的ソート)

Python のリストソートいろいろ

Python3 でリストのソートを行う方法をまとめます。この記事でまとめるのは以下の方法です。

  • 非破壊的ソート
  • 破壊的ソート
  • 降順にソート
  • クラスの特定の値を使ってソート
  • タプルをソート
  • 複数キーを使ったソート

組み込み関数の sorted()

Python の組み込み関数 sorted() を使ってリストをソートすることが可能です。sorted() は引数で渡されたリストのソート結果を、新しく生成した配列に格納して返します。

array = [3, 1, 4, 1, 5, 9, 2, 6]

result = sorted(array)

print(array)  # [3, 1, 4, 1, 5, 9, 2, 6]
print(result) # [1, 1, 2, 3, 4, 5, 6, 9]

ソートされるリストの状態は変更されないことに注意してください。新しく生成されたリストにソート結果が格納されています。

非破壊的なソート を行いたい場合は組み込み関数の sorted() を使いましょう。

リストの持つメソッド sort()

リスト型はソートメソッド sort() を持ちます。これを使うことでリストの状態を書き換えてソートを行います。つまり 破壊的なソート を行います。

前述の組み込み関数 sorted() との違いは破壊的ソートを行うかどうかです。

array = [3, 1, 4, 1, 5, 9, 2, 6]

array.sort()
print(array) # [1, 1, 2, 3, 4, 5, 6, 9]

sort() を呼び出した array の中身が直接ソートされた結果に書き換えられています。

降順(逆順)にソートする

前述の sort()sorted() も、引数で降順(逆順)にソートすることができます。reverse=True と指定します。

array = [3, 1, 4, 1, 5, 9, 2, 6]
result = sorted(array, reverse=True)

print(result) # [9, 6, 5, 4, 3, 2, 1, 1]
array = [3, 1, 4, 1, 5, 9, 2, 6]

array.sort(reverse=True)
print(array) # [9, 6, 5, 4, 3, 2, 1, 1]

クラスの特定の値を使ってソート

クラスが格納されたリストをソートしたい場合はいくつか方法があります。

key に attrgetter を使う

ソート時に引数で key を指定します。 attrgetter でソートする際に用いるキーとなる属性を指定できます。たとえば以下のようなクラスが格納されたリストをソートする例を考えます。

class Human:
    def __init__(self, name, age):
        self.name = name
        self.age = age

名前と年齢の2つの値を持つクラスです。このクラスのリストを年齢でソートする場合は以下のように書けます。

from operator import itemgetter

a = Human('taro', 20)
b = Human('jiro', 10)
c = Human('hanako', 15)
array = [a, b, c]

# age をキーにソート
result = sorted(array, key=attrgetter('age'))
# array.sort(key=attrgetter('age'))

for h in result:
    print(vars(h))

# {'name': 'jiro', 'age': 10}
# {'name': 'hanako', 'age': 15}
# {'name': 'taro', 'age': 20}

itemgetter を import するのをお忘れなく。sort() を使う場合も同じく key を指定してください。

key に lamda を使う

lambda を使って直接比較するキーを取り出す式を指定できます。

a = Human('taro', 20)
b = Human('jiro', 10)
c = Human('hanako', 15)

array = [a, b, c]

result = sorted(array, key=lambda h: h.age)
# array.sort(key=lambda h: h.age)

for h in result:
    print(vars(h))
# {'name': 'jiro', 'age': 10}
# {'name': 'hanako', 'age': 15}
# {'name': 'taro', 'age': 20}

タプルをソートする

タプルのリストと同様にソートできます。ただしタプルは変更不可なので soted() しか使えません。

sorted()

tup = (3, 1, 4, 1, 5)

result = sorted(tup)

print(result)        # [1, 1, 3, 4, 5]
print(tuple(result)) # (1, 1, 3, 4, 5)

タプルに対して sorted() を使ってソートすると、リストでソート結果が返されます。結果はリストで返されるので、タプルにしたければご自由に。

複数キーでのソート

複数キーでソートするには、タプルにした値をキーにソートします。タプルのソートは1つ目の値から順番に比較していくので、結果いい感じに複数キーでのソートになります。

a = Human('taro', 20)
b = Human('taro', 10)
c = Human('hanako', 15)
array = [a, b, c]

result = sorted(array, key=lambda h: (h.name, h.age))

for h in result:
    print(vars(h))

# {'name': 'hanako', 'age': 15}
# {'name': 'taro', 'age': 10}
# {'name': 'taro', 'age': 20}

この方法だと複合キーすべてに対して昇順(降順)になります。個別のキーに対して昇順(降順)を指定したい場合、優先度の低いキー順にソートを複数回実行すればよいです。

もちろん処理コストは余計にかかります。

a = Human('taro', 20)
b = Human('taro', 10)
c = Human('hanako', 15)
array = [a, b, c]

array.sort(key=attrgetter('age'))
array.sort(key=attrgetter('name'))

for h in array:
    print(vars(h))

# {'name': 'hanako', 'age': 15}
# {'name': 'taro', 'age': 10}
# {'name': 'taro', 'age': 20}

以上。

Pythonカテゴリの最新記事