はじめに
先日仕事中にスラッシュ区切りの数字をソートしたいけどうまくできない!ということがありました。
調べても出てこなかったので備忘録として残しておきます。
普通にソートすると・・・
例えばstr型のスラッシュ区切りの数字のリストにsort関数でソートをかけると以下のような結果になります。
コード
slash_num_list = ["1/2", "1/3", "1/1", "1/10", "1/30", "1/20"]
slash_num_list.sort()
print(slash_num_list)
実行結果
["1/1", "1/10", "1/2", "1/20", "1/3", "1/30"]
私が期待する並び方は["1/1", "1/2", "1/3", "1/10", "1/20", "1/30"]
だったのですが、str型ではその並びは実現できないことがわかりました。
きれいにソートする方法
sort()は内部的に<演算子を利用する
Pythonのドキュメントを見るとsort()では<演算子を利用していると書かれています。
https://docs.python.org/ja/3/library/stdtypes.html?highlight=sort#list.sort
リストの大小比較を利用する
ところで、Pythonではリスト同士を比較した場合、インデックス0の要素から順に比較して最初の異なる要素の大小の結果が全体の結果として反映されます。
例えば以下の以下の二つのint型のリストを比較してみると
list1 = [1, 1]
list2 = [1, 2]
print(list1 > list2)
print(list1 < list2)
実行結果は以下のようになります。
False
True
list1とlist2を比較する場合、インデックス0の要素はどちらも1なので次の要素に移動します。
インデックス1の要素は1と2で異なるのでこの大小がリスト同士の比較の結果になるのです。
上記二つを組み合わせる
つまり、スラッシュ区切りの数字を比較するにはそれぞれをint型のリストにしたうえでsort()関数を使えば期待した並びになるわけです。
# スラッシュ区切りの数字をそれぞれリストにして、それらを一つのリストに入れる。
slash_num_list = ["1/2", "1/3", "1/1", "1/10", "1/30", "1/20"]
converted_list = []
for slash_num in slash_num_list:
splited_slash_num = slash_num.split("/")
converted_num = [int(splited_slash_num[0]), int(splited_slash_num[1])]
converted_list.append(converted_num)
converted_list.sort()
print(converted_list)
# ソートした結果をstr型に戻す
result_list = []
for converted_num in converted_list:
slash_num = f"{converted_num[0]}/{converted_num[1]}"
result_list.append(slash_num)
print(result_list)
実行結果は以下のようになります。きれいに並び替えられています。
[[1, 1], [1, 2], [1, 3], [1, 10], [1, 20], [1, 30]]
['1/1', '1/2', '1/3', '1/10', '1/20', '1/30']