Python

[python] pythonでリストソートのベストプラクティス(Best practice for sorting list in python)

ソート方法

リストをソートするには、

  • リストの組み込みメソッド sort()
  • 組み込み関数 sorted()

2つの方法 があります。

両者の違いは、元の リスト自体が書き換えられるか にあります。

sort() は 元のリスト自体が書き換えられるのに対して、
sorted() は元のリストを変更せず新しいリストを返します。

sort()の使用例

org_list = [6, 1, 4, 5, -4]

org_list.sort()
print(org_list)
# [-4, 1, 4, 5, 6]

sorted() の使用例

org_list = [6, 1, 4, 5, -4]

new_list = sorted(org_list)
print(org_list)
print(new_list)
# [6, 1, 4, 5, -4]
# [-4, 1, 4, 5, 6]

ソートキーの指定方法

[6, 1, 4, 5, -4] のような1次元の単純リストには
特にソートキーを指定する必要はないが、

下記のように 多次元のリスト や 要素が辞書などのObjectだったりすると、
ソートキーを指定する必要が出て来ます。

  • 多次元のリスト例
[[1,2,3], [3,4,5], [2,3,4]]
  • 要素が辞書Objectのリスト
[
    {'name': 'wang', 'age': 30, 'score': 80},
    {'name': 'sato', 'age': 40, 'score': 90},
    {'name': 'nakata', 'age': 40, 'score': 70},
]

(1). ラムダ式で指定

ラムダ関数のため、ソートキーを好きなように設定可能です。

ケース1

先ほど例にあったリストを複数のキーでソートしたければ、
下記のように指定すると、リストは ageでソートされ、
age が同じの場合、 score でソートします。

students = [
    {'name': 'wang', 'age': 30, 'score': 80},
    {'name': 'sato', 'age': 40, 'score': 90},
    {'name': 'nakata', 'age': 40, 'score': 70},
]

students_sorted = sorted(students, key=lambda x: (x["age"], x["score"],))

print(students)
print(students_sorted) 
# [{'name': 'wang', 'score': 80, 'age': 30}, {'name': 'sato', 'score': 90, 'age': 40}, {'name': 'nakata', 'score': 70, 'age': 40}]
# [{'name': 'wang', 'score': 80, 'age': 30}, {'name': 'nakata', 'score': 70, 'age': 40}, {'name': 'sato', 'score': 90, 'age': 40}]

ケース2

リストの要素の属性をキーでソートする例です。

from datetime import date
values = [
    date(2017, 12, 1),
    date(2015, 11, 3),
    date(2016, 10, 3),
]
sorted(values, key=lambda x: (x.month, x.day,))
# [datetime.date(2016, 10, 3), 
#  datetime.date(2015, 11, 3), 
#  datetime.date(2017, 12, 1)]

ケース3

多次元リストの要素の 0番目の値をキー としてソート例です。

list_2d = [[1, 2, 3], [9, 8, 7], [4, 5, 6]]
list_2d_sorted = sorted(list_2d, key=lambda x: x[0])
print(list_2d)
print(list_2d_sorted)
# [[1, 2, 3], [9, 8, 7], [4, 5, 6]]
# [[1, 2, 3], [4, 5, 6], [9, 8, 7]]

ケース4

例えば、リストを2つのキーの差分でソートしたければ、
下記のように指定します。

students = [
    {'name': 'wang', 'age': 30, 'score': 80},
    {'name': 'sato', 'age': 40, 'score': 100},
    {'name': 'nakata', 'age': 40, 'score': 70},
]

students_sorted = sorted(students, key=lambda x: x["score"] - x["age"])

print(students)
print(students_sorted)
# [{'name': 'wang', 'score': 80, 'age': 30}, {'name': 'sato', 'score': 100, 'age': 40}, {'name': 'nakata', 'score': 70, 'age': 40}]
# [{'name': 'nakata', 'score': 70, 'age': 40}, {'name': 'wang', 'score': 80, 'age': 30}, {'name': 'sato', 'score': 100, 'age': 40}]

(2). itemgetterやattrgetterで指定

ラムダ関数のように自由に設定は出来ず
特定の条件の場合しか設定できないです。

ケース1

from operator import itemgetter

students_sorted = sorted(students, key=itemgetter('age', 'score'))

print(students)
print(students_sorted)
# [{'age': 30, 'score': 80, 'name': 'wang'}, {'age': 40, 'score': 90, 'name': 'sato'}, {'age': 40, 'score': 70, 'name': 'nakata'}]
# [{'age': 30, 'score': 80, 'name': 'wang'}, {'age': 40, 'score': 70, 'name': 'nakata'}, {'age': 40, 'score': 90, 'name': 'sato'}]

ケース2

from operator import attrgetter
sorted(values, key=attrgetter('month', 'day'))
# [datetime.date(2016, 10, 3), 
#  datetime.date(2015, 11, 3), 
#  datetime.date(2017, 12, 1)]

ケース3

from operator import itemgetter

list_2d = [[1, 2, 3], [9, 8, 7], [4, 5, 6]]
list_2d_sorted = sorted(list_2d, key=itemgetter(0))
print(list_2d)
print(list_2d_sorted)
# [[1, 2, 3], [9, 8, 7], [4, 5, 6]]
# [[1, 2, 3], [4, 5, 6], [9, 8, 7]]

ケース4

itemgetterやattrgetterでは実現できないです。

参考

https://note.nkmk.me/python-list-sort-sorted/
https://qiita.com/tag1216/items/485217b5c88dfcf00d34

コメントを残す