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 Person
s 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)})