45295

[code]

    class A:
       def __init__(self, age, name):
           self.__age=age
           self.__name=name
       ...
       def record(self):
           return {'age':age,'name':name}
    
    class Alist:
       def __init__(self, A):
           self.__a_list = [A]
    
       # あたらしくクラスAを代入する処理が続く
    
[/code]

のような Python3.5 のコードがあるとして  
Alistクラスを他のクラスを使って、Aの特定のキーでソートしたい時どのように実装すればよいでしょうか？


CC BY-SA 4.0
2018-07-02T22:50:25.017
45245
2018-07-04T03:33:19.260
19500
question
python python3 sort
クラスのリストをインスタンス変数に持つクラスのソートがしたい


整数のリストのソートであれば、整数同士を大小比較しますよね。  
質問は、「オブジェクトのリストのソートで、オブジェクトのインスタンス変数の値でソートしたい」という事ですから、整数同士の大小比較をしていた部分を、インスタンス変数の値の大小比較にすれば良いわけです。

バブルソートのコード(ネット上から拝借)の大小比較の部分『if arr[i] > arr[i + 1]:』を

[code]

    def bubble_sort(arr):
    change = True
    while change:
        change = False
        for i in range(len(arr) - 1):
            if arr[i] > arr[i + 1]:
                arr[i], arr[i + 1] = arr[i + 1], arr[i]
                change = True
    return arr
    
[/code]

を『if arr[i].age > arr[i + 1].age:』に変更すれば、Aクラスのインスタンス変数ageでソートされるようになります。

テスト用データを作って、ageおよびnameでソートするコードを書いてみました。

[code]

    class A:
        def __init__(self, age, name):
            self.age=age
            self.name=name
    
    #クラスAのインスタンス変数ageでソートしたリストを返す関数
    def bubble_sort_age(arr):
        change = True
        while change:
            change = False
            for i in range(len(arr) - 1):
                if arr[i].age > arr[i + 1].age:
                    arr[i], arr[i + 1] = arr[i + 1], arr[i]
                    change = True
        return arr
    
    #クラスAのインスタンス変数ageでソートしたリストを返す関数
    def bubble_sort_name(arr):
        change = True
        while change:
            change = False
            for i in range(len(arr) - 1):
                if arr[i].name > arr[i + 1].name:
                    arr[i], arr[i + 1] = arr[i + 1], arr[i]
                    change = True
        return arr
    
    #クラスAのリストを表示する関数
    def print_listOfA(arr):
        print("No. \t Age \t Name")
        for i in range(len(arr)):
            print(i+1, "\t",arr[i].age, "\t",arr[i].name)
        print()
    
    
    #List of class A objects
    list=[]
    
    #Sample data (ageでソートしてみる対象）
    list += [A(18,"Yamamoto")]
    list += [A(23,"Tanaka")]
    list += [A(56,"Minami")]
    list += [A(32,"Akiyama")]
    list += [A(43,"Sato")]
    list += [A(12,"Suzuki")]
    
    print("ソート前のリスト")
    print_listOfA(list)
    
    #ageでソート（バブルソート)
    list_ageOrder = bubble_sort_age(list)
    print("ageでソート後のリスト")
    print_listOfA(list_ageOrder)
    
    #nameでソート（バブルソート)
    print("nameでソート後のリスト")
    list_nameOrder = bubble_sort_name(list)
    print_listOfA(list_nameOrder)
    
[/code]

実行結果:

> ソート前のリスト  
>  No. Age Name  
>  1 18 Yamamoto  
>  2 23 Tanaka  
>  3 56 Minami  
>  4 32 Akiyama  
>  5 43 Sato  
>  6 12 Suzuki  
>  ageでソート後のリスト  
>  No. Age Name  
>  1 12 Suzuki  
>  2 18 Yamamoto  
>  3 23 Tanaka  
>  4 32 Akiyama  
>  5 43 Sato  
>  6 56 Minami  
>  nameでソート後のリスト  
>  No. Age Name  
>  1 32 Akiyama  
>  2 56 Minami  
>  3 43 Sato  
>  4 12 Suzuki  
>  5 23 Tanaka  
>  6 18 Yamamoto


CC BY-SA 4.0
2018-07-04T02:42:37.097
45292
2018-07-04T02:42:37.097
217
45245
answer


こんなんどうでしょうか。

[sorted関数](https://docs.python.jp/3/howto/sorting.html#sortinghowto)で検索対象とするキーを関数で指定できるようです。  
それを利用して、Alist に sort_by_age, sort_by_name メソッドを追加してみました。

[code]

    class A:
       def __init__(self, age, name):
          self.__age=age
          self.__name=name
    
       def record(self):
           return {'age':age,'name':name}
    
       # 内部変数をアクセス可能に
       @property
       def age(self):
          return self.__age
    
       @property
       def name(self):
          return self.__name
    
       # printしたときに見やすいように
       def __repr__(self):
          return "<A age:%d,name:%s>" % (self.__age, self.__name)
    
    
    class Alist:
       def __init__(self, obj):
           self.__a_list = [obj]
    
       def add(self, obj):
          self.__a_list.append(obj)
    
       # 年齢でソートした配列を返却
       def sort_by_age(self):
          return sorted(self.__a_list, key=lambda a: a.age)
    
       # 名前でソートした配列を返却
       def sort_by_name(self):
          return sorted(self.__a_list, key=lambda a: a.name)
    
[/code]

利用例は以下になります。

[code]

    a1 = A(2, 'b_san')
    a2 = A(1, 'c_san')
    a3 = A(3, 'a_san')
    
    alist = Alist(a1)
    alist.add(a2)
    alist.add(a3)
    
    print(alist.sort_by_age()) #=> [<A age:1,name:c_san>, <A age:2,name:b_san>, <A age:3,name:a_san>]
    print(alist.sort_by_name()) #=> [<A age:3,name:a_san>, <A age:2,name:b_san>, <A age:1,name:c_san>]
    
[/code]


CC BY-SA 4.0
2018-07-04T03:33:19.260
45295
2018-07-04T03:33:19.260
45245
answer