やりたかったこと
pythonで簡単なクラスを定義して,そのクラスの中のある変数を基準にしてインスタンスが入っているリストのソートを行いたかったです.
どうやるんだっけ?となったのでやり方をメモしておきます.
作成したクラス
class Node: # 木のノードを表すクラス
def __init__(self, value: int, left = None, right = None):
self.value: int = value # ソートの基準としたい値
self.left = left # 左の子ノード
self.right = right # 右の子ノード
このクラスのvalueというint型の変数をもとに大小判定をしてリストをソートしたいです.
ソートするためにこのクラスのインスタンスのリストを適当に作成しておきます.
> import numpy as np
> nodes = [Node(np.random.randint(10)) for i in range(10)]
> print([node.value for node in nodes])
[6, 1, 7, 9, 8, 6, 4, 9, 6, 7]
このnodes
というリストを単純にソートしてみると...
> sorted(nodes)
TypeError: '<' not supported between instances of 'Node' and 'Node'
このようにTypeErrorがでてソートすることができません.
Node
インスタンス間の比較演算<
がサポートされていないというエラーがでています.
やり方1: クラスに__lt__
メソッドを定義する
class Node: # 木のノードを表すクラス
def __init__(self, value: int, left = None, right = None):
self.left = left # 左の子ノード
self.right = right # 右の子ノード
self.value: int = value # ソートの基準としたい値
def __lt__(self, other): # 自作クラスで大小を判別するための関数
return self.value < other.value
上記のように__lt__
メソッド(less than)を定義します.
引数にはself
とother
を受け取ります.
self.value
がother.value
より小さい時にはTrue
をそうで無い時はFalse
を返すようにします.
このように定義することでインスタンス間の大小を比較できるようになります.
(そのほかにも__eq__
(equal)や__gt__
(greater than)などの比較演算を定義できますが,ソートなら__lt__
を定義しておけば十分でした.)
実際にソートしてみると...
> sorted_nodes = sorted(nodes)
> print([node.value for node in sorted_nodes])
[1, 4, 6, 6, 6, 7, 7, 8, 9, 9]
正しくソートされていました!
やり方2: ソート時に比較する際のキーを渡す
pythonのsorted
関数ではオプション引数としてkey
を渡すことができます.
このkey
を渡すとこれを基準にソートを行なってくれます.
次のようにlambda式を使って書けます.
> sorted_nodes = sorted(nodes, key=lambda x: x.value)
> print([node.value for node in sorted_nodes])
[1, 4, 6, 6, 6, 7, 7, 8, 9, 9]
こちらも正しくソートされていました.
まとめ
上記2つのやり方どちらでもソートを行うことができます.
単純にソートをしたいだけならやり方2の方が早く書けると思います.
ただ優先度付きキューなどに入れたい場合やり方1を用いないとできないと思います.