【Python】文字列と数字の混在リストのソート
Pythonにはリストの並び替えをする関数が用意されていますが、以下のような文字列に数字が含まれているリストの並び替えでは期待通りの結果を得られませんでした。
lst = ["x2", "x32", "x100", "x13", "x1", "x21"] sorted(lst)
結果
>> ['x1', 'x100', 'x13', 'x2', 'x21', 'x32']
期待している結果は
>> ['x1', 'x2', 'x13', 'x21', 'x32', 'x100']
やりたいことは「文字列だけれども数値の昇順ソート」です。
そのためには「桁の大きい数値は後ろへ」まわすことが必要です。
そこで、「文字列の長さを比較してから文字列同士を比較」する処理を試します。
def main(lst): print("before = ", lst) sorted_list = my_sort(lst) print("after = ", sorted_list) def my_sort(lst): buf_list = sort_length(lst) sorted_list = sort_strings(buf_list) return sorted_list def sort_strings(lst): str_sorted = bubble_sort(lst, "strings") return str_sorted def sort_length(lst): len_sorted = bubble_sort(lst, "length") return len_sorted def bubble_sort(lst, mode): n = len(lst) for i in range(n): for j in range(n-1, i, -1): if mode == 'length': if len(lst[j]) < len(lst[j-1]): tmp = lst[j] lst[j] = lst[j-1] lst[j-1] = tmp elif mode == 'strings': if len(lst[j]) == len(lst[j-1]): if lst[j] < lst[j-1]: tmp = lst[j] lst[j] = lst[j-1] lst[j-1] = tmp return lst if __name__ == '__main__': lst = ["x2", "x32", "x100", "x13", "x1", "x21"] main(lst) lst = ["5", "11", "9", "101", "51", "36"] main(lst)
結果は以下のようになりました。
>> before = ['x2', 'x32', 'x100', 'x13', 'x1', 'x21'] >> after = ['x1', 'x2', 'x13', 'x21', 'x32', 'x100'] >> before = ['5', '11', '9', '101', '51', '36'] >> after = ['5', '9', '11', '36', '51', '101']
今回行った処理は文字列の長さに対してソート(関数:sort_length(lst))してから
文字列の長さが同じ場合に限りソート(関数:sort_strings(lst))をしました。
ソートの手法はバブルソートを用いました。
まとめ
「文字列の長さを比較してから文字列同士を比較」する処理によって数値を含む文字列のソートができました。
マクロの問題点
(1)今回試したマクロではリストの要素に大文字、小文字が混在している場合のソートが上手く働きません。
before = ['xyz', 'ABC', 'STU', 'abc', 'ghi'] after = ['ABC', 'STU', 'abc', 'ghi', 'xyz']
['ABC', 'abc', 'ghi', 'STU', 'xyz']とはなりません。
(2)また、ソートの手法にバブルソートを用いているので計算量がO(N^2)となり、長いリストの処理に時間がかかります。
問題(1)、(2)に関しては別の記事で試してみたいと思います。