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']