0
0

More than 1 year has passed since last update.

python key関数を用いたソートを行おう!(備忘録)

Last updated at Posted at 2022-12-06

sortメソッドについて

組み込み型にlistは、いろいろな基準でlistの要素を順序で整列するsortメソッドが存在する!

# sort()を用いてlist内の要素を小さいものから大きいものに並び変える
numbers = [100, 38, 2, 13, 67]
numbers.sort()
print(numbers)



# 出力結果
>>>
[2, 13, 38, 67, 100]

sortメソッドは、文字列や、浮動小数点数などでは動作するが、オブジェクトでは動作しない。

class stationary:
    def __init__(self, name, weight):
        self.name = name
        self.weight = weight

    def __repr__(self):
        return f'stationary({self.name!r}, {self.weight})'
    
various_stationery = [
    stationary('pen', 10),
    stationary('eraser', 20),
    stationary('notebook', 1000),
    stationary('wcissors', 32),
]

various_stationery.sort()


# 出力結果
>>>
TypeError: '<' not supported between instances of 'stationary' and 'stationary'

クラスには、数字やアルファベットといった、自然に?並び替えられる順序がないため、並び替えができない。
そこで、オブジェクトで順序付けを行う。sortメッソドにkey関数を用いる。
<f文字列中の「!r」について>
⇒f文字列内の{}を評価する際に、呼び出すメソッドを定義するためのもの。[!r]でreprメソッド、[!s]でstrメッソド、[!a]でasciiメソッド。

key関数を使おう

key関数を用いて名前順(アルファベット順)にソートしてみる

class stationary:
    def __init__(self, name, weight):
        self.name = name
        self.weight = weight

    def __repr__(self):
        return f'stationary({self.name!r}, {self.weight})'
    
various_stationery = [
    stationary('pen', 10),
    stationary('eraser', 20),
    stationary('notebook', 1000),
    stationary('wcissors', 32),
]

print('Unsorted', repr(various_stationery))
print('*'*25)
various_stationery.sort(key=lambda x: x.name)
print('Sorted:', various_stationery)



# 出力結果
>>>
Unsorted [stationary('pen', 10), stationary('eraser', 20), stationary('notebook', 1000), stationary('wcissors', 32)]
*************************
Sorted: [stationary('eraser', 20), stationary('notebook', 1000), stationary('pen', 10), stationary('wcissors', 32)]

以下、f文字列の「!r」を外したバージョン

# 出力結果
>>>
Unsorted [stationary(pen, 10), stationary(eraser, 20), stationary(notebook, 1000), stationary(wcissors, 32)]
*************************
Sorted: [stationary(eraser, 20), stationary(notebook, 1000), stationary(pen, 10), stationary(wcissors, 32)]

nameの部分にシングルクォーテーションがついてないことがわかります。

weight(重さ)でのソートも以下のように、できる

print('Unsorted', repr(various_stationery))
print('*'*25)
various_stationery.sort(key=lambda x: x.weight)
print('Sorted:', various_stationery)


# 出力結果
>>>
Unsorted [stationary('pen', 10), stationary('eraser', 20), stationary('notebook', 1000), stationary('wcissors', 32)]
*************************
Sorted: [stationary('pen', 10), stationary('eraser', 20), stationary('wcissors', 32), stationary('notebook', 1000)]

複数の基準でソートする

先ほどの文房具を名前順や重さ順単体の基準でソートするだけでなく、名前順と重さ順2つの基準を持ったソートを行う。
このような場合では、tuple型(タプル型)を用いる。タプルの比較は、左の要素から順々に比べられていく。

以下タプルの比べ方

# 左から各要素で比べていく。「こんにちわ」の文字数が多いのでTrue
('おはよう', 6) < ('こんにちわ', 6)
>>>True

# 「いただきます」と「ごちそうさま」の文字数はともに6文字。次に「6」と「8」を比べて「8」が大きいのでTrue
('いただきます', 6) < ('ごちそうさま', 8)
>>>True

タプルの比較方式を用いて重さ順で並べ、さらに名前順で並べる

class stationary:
    def __init__(self, name, weight):
        self.name = name
        self.weight = weight

    def __repr__(self):
        return f'stationary({self.name!r}, {self.weight})'
    
various_stationery = [
    stationary('pen', 10),
    stationary('eraser', 20),
    stationary('pencil_case', 1500),
    stationary('pencil_sharpener', 1000),
]


print('Unsorted', repr(various_stationery))
print('*'*25)
various_stationery.sort(key=lambda x: (x.weight, x.name))
print('Sorted:', various_stationery)

>>>
Unsorted [stationary('pen', 10), stationary('eraser', 20), stationary('pencil_case', 1500), stationary('pencil_sharpener', 1000)]
*************************
Sorted: [stationary('pen', 10), stationary('eraser', 20), stationary('pencil_sharpener', 1000), stationary('pencil_case', 1500)]

以下、名前順のみの場合

print('Unsorted', repr(various_stationery))
print('*'*25)
various_stationery.sort(key=lambda x: x.name)
print('Sorted:', various_stationery)


>>>
Unsorted [stationary('pen', 10), stationary('eraser', 20), stationary('pencil_case', 1500), stationary('pencil_sharpener', 1000)]
*************************
Sorted: [stationary('eraser', 20), stationary('pen', 10), stationary('pencil_case', 1500), stationary('pencil_sharpener', 1000)]

比べてみると「pecil_case」と「pencil_sharpener」の順序が変わっていることがわかる。

昇順から降順にしてみよう

reverse=Trueを追加すると昇順から降順にできる。

class stationary:
    def __init__(self, name, weight):
        self.name = name
        self.weight = weight

    def __repr__(self):
        return f'stationary({self.name!r}, {self.weight})'
    
various_stationery = [
    stationary('pen', 10),
    stationary('eraser', 20),
    stationary('pencil_case', 1500),
    stationary('pencil_sharpener', 1000),
]


print("Unsorted", repr(various_stationery))
print('*'*25)
various_stationery.sort(key=lambda x: (x.weight, x.name), reverse=True)
print("Sorted:", various_stationery)


>>>
Unsorted [stationary('pen', 10), stationary('eraser', 20), stationary('pencil_case', 1500), stationary('pencil_sharpener', 1000)]
*************************
Sorted: [stationary('pencil_case', 1500), stationary('pencil_sharpener', 1000), stationary('eraser', 20), stationary('pen', 10)]

マイナス単項演算子をつけて昇順と降順の両立させる

reverse=Trueでは名前と重さ両方を逆にしたが「-」を用いることで、片方の要素に対して逆順にできる。
ちなみに、マイナス単項演算子はすべての型には使えず、nameに用いようとするとエラーが出力される。

print("Unsorted", repr(various_stationery))
print('*'*25)
various_stationery.sort(key=lambda x: (-x.weight, x.name))
print("Sorted:", various_stationery)

>>>
Unsorted [stationary('pen', 10), stationary('eraser', 20), stationary('pencil_case', 1500), stationary('pencil_sharpener', 1000)]
*************************
Sorted: [stationary('pencil_case', 1500), stationary('pencil_sharpener', 1000), stationary('eraser', 20), stationary('pen', 10)]

大文字と小文字のソート

大文字と小文字をソートしようとすると、大文字⇒小文字の順で並び変えられる

place = ['America', 'asia', 'Japan', 'jamaica']
place.sort()
print(place)

>>>
['America', 'Japan', 'asia', 'jamaica']

lowerメソッドを適用すると大文字小文字関係なくソートができるようになる。

place = ['America', 'asia', 'Japan', 'jamaica']
place.sort(key=lambda x: x.lower())
print(place)

>>>
['America', 'asia', 'jamaica', 'Japan']
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0