ベスパリブ

プログラミングを主とした日記・備忘録です。ベスパ持ってないです。

リストの要素がクラスオブジェクトの場合のソート(Python)

リストの要素がクラスオブジェクトの場合に、そのオブジェクトのメンバ変数に対してソートをしたい。

クラスに対するソート(と言ったら語弊があるけど)。

やりたいこと

class Person():
    
    def __init__(self, _id, height, name):
        self._id = _id
        self._height = height
        self._name = name

def solve():
    N = 5
    p = [None] * N
    p[0] = Person(5, 160, "うえだ")
    p[1] = Person(2, 140, "いいだ")
    p[2] = Person(4, 140, "えのもと")
    p[3] = Person(1, 150, "あすのざか")
    p[4] = Person(3, 160, "おおの")

    # このとき、pをPersonのid順などでソートしたい

def __name__ == "__main__":
    solve()

コード

# coding: utf-8
class Person():
    
    def __init__(self, _id, height, name):
        self._id = _id
        self._height = height
        self._name = name
        self.latest_me = None # 最近振った目の数

    @property
    def id(self):
        return self._id
    
    @property
    def height(self):
        return self._height
    
    @property
    def name(self):
        return self._name
    
    def toss_dice(self):
        """ 1~6の目のサイコロを振り、出た目の数を返す """
        import random
        self.latest_me = random.randrange(1, 7)
        return self.latest_me


def sort_height(p, N):
    print("--背の順でソートする--")

    # lambdaを使う場合
    sorted_p = sorted(p, key=lambda person: person.height)

    # operator.attrgetterを使う場合(結果はlambdaを使った場合と同じ)
    from operator import attrgetter
    sorted_p = sorted(p, key=attrgetter("height"))

    for i in range(N):
        print("{}, {}, {}".format(sorted_p[i].id, sorted_p[i].height, sorted_p[i].name))


def sort_height_and_id(p, N):
    print("--背の順でソートし、かつ、idが若い順にソートする(身長が同じ人はidが若い順に並ぶ)--")
    
    from operator import attrgetter
    sorted_p = sorted(p, key=attrgetter("height", "id"))

    for i in range(N):
        print("{}, {}, {}".format(sorted_p[i].id, sorted_p[i].height, sorted_p[i].name))


def sort_dice(p, N):
    print("--サイコロを振り、出た目の数でソートする(実行するたびに変わる)--")
    
    # lambdaを使う場合
    sorted_p = sorted(p, key=lambda person: person.toss_dice())
    
    # operator.methodcallerを使う場合(結果はlambdaを使った場合と同じ)
    from operator import methodcaller
    sorted_p = sorted(p, key=methodcaller("toss_dice"))

    for i in range(N):
        print("{}, {}, {} : D{}".format(sorted_p[i].id, sorted_p[i].height, sorted_p[i].name, sorted_p[i].latest_me))


def solve():
    N = 5
    p = [None] * N
    p[0] = Person(5, 160, "うえだ")
    p[1] = Person(2, 140, "いいだ")
    p[2] = Person(4, 140, "えのもと")
    p[3] = Person(1, 150, "あすのざか")
    p[4] = Person(3, 160, "おおの")

    # 単純に表示する
    for i in range(N):
        print("{}, {}, {}".format(p[i].id, p[i].height, p[i].name))
    
    # 背の順でソート
    sort_height(p, N)

    # 背の順でソートし、かつ、idが若い順にソートする(身長が同じ人はidが若い順に並ぶ)
    sort_height_and_id(p, N)

    # サイコロを振り、出た目の数でソートする(実行するたびに変わる)
    sort_dice(p, N)

if __name__ == "__main__":
    solve()

↓結果

5, 160, うえだ
2, 140, いいだ
4, 140, えのもと
1, 150, あすのざか
3, 160, おおの
--背の順でソートする--
2, 140, いいだ
4, 140, えのもと
1, 150, あすのざか
5, 160, うえだ
3, 160, おおの
--背の順でソートし、かつ、idが若い順にソートする(身長が同じ人はidが若い順に並ぶ)--
2, 140, いいだ
4, 140, えのもと
1, 150, あすのざか
3, 160, おおの
5, 160, うえだ
--サイコロを振り、出た目の数でソートする(実行するたびに変わる)--
2, 140, いいだ : D1
3, 160, おおの : D1
5, 160, うえだ : D3
4, 140, えのもと : D3
1, 150, あすのざか : D4

おまけ

参考URL:

docs.python.org