Home > Software design >  Sort the dictonary of objects by the attribute of the obejct
Sort the dictonary of objects by the attribute of the obejct

Time:03-12

A dictionary that has a key, the value it is a object of class with attributes

dic = { 1:Person("John, Greenberg", 3), 
        2:Person("Thomas, San", 5), 
        3:Person("Annie, Dawn", 7) }


class Person:
    def __init__(self, name, total_hour):
         self.name = name
         self.total_hour = total_hour

How to sort the dictionary by the object's attribute 'name'?

Expected output:

dic = { 3:Person("Annie, Dawn", 7), 
        1:Person("John, Greenberg", 3), 
        2:Person("Thomas, San", 5) }

CodePudding user response:

"Sorting" a dictionary and having all its keys be numbers are sort of a "smell" that you're using the wrong data structure -- are you sure you don't want to keep these Persons in a list rather than a dict?

That said, you can "sort" a dict in Python (as of version 3.7) by sorting its items() and then using the sorted items to recreate a fresh dict, since a dict preserves the insertion order of its keys:

>>> class Person:
...     def __init__(self, name, total_hour):
...          self.name = name
...          self.total_hour = total_hour
...
>>> dic = { 1:Person("John, Greenberg", 3),
...         2:Person("Thomas, San", 5),
...         3:Person("Annie, Dawn", 7) }
>>> dict(sorted(dic.items(), key=lambda i: i[1].name))
{3: <__main__.Person object at 0x00000239E799AE90>, 1: <__main__.Person object at 0x00000239E7999FF0>, 2: <__main__.Person object at 0x00000239E799AE30>}

CodePudding user response:

As you may note from seeing other questions tagged sorteddictionary, sortedcollections has a ValueSortedDict type. If you only want to sort the dict once, Samwise's answer above is perfectly serviceable (for Python 3.7 , otherwise use a collections.OrderedDict to hold your sorted values). But if you want your dict to stay sorted as you add more elements, a ValueSortedDict is the way to go.

A good way to enable objects in your person class to be sorted by their attributes is to add comparison magic methods (__eq__, __le__, __ge__ and so forth) to your class, or use a dataclasses.dataclass to enable comparison of your objects by one or more attributes.

>>> import dataclasses
>>> from sortedcollections import ValueSortedDict
>>> @dataclasses.dataclass(order=True)
... class Person:
...     name: str # by default, this is factored into the sort order
...     total_hour: int = dataclasses.field(compare=False) # disable sorting by total_hour
...
>>> dic = { 1:Person("John, Greenberg", 3),
...     2:Person("Thomas, San", 5),
...     3:Person("Annie, Dawn", 7) }
>>> sdic = ValueSortedDict(dic)
>>> sdic
ValueSortedDict(None, {3: Person(name='Annie, Dawn', total_hour=7), 1: Person(name='John, Greenberg', total_hour=3), 2: Person(name='Thomas, San', total_hour=5)})
>>> sdic[4] = Person('Bezos, Jeff', 6)
>>> sdic
ValueSortedDict(None, {3: Person(name='Annie, Dawn', total_hour=7), 4: Person(name='Bezos, Jeff', total_hour=6), 1: Person(name='John, Greenberg', total_hour=3), 2: Person(name='Thomas, San', total_hour=5)})
  • Related