pythonpython-datetimeordereddict

OrderedDict sorting incorrectly


As I understand it, the following should result in an OrderedDict object with the items sorted by the key, which is a datetime object.

ledger = OrderedDict(
    sorted(ledger.items(), key=lambda x: datetime.strftime(x[0], '%d-%m-%Y'))
)

However, in my case, the objects are being sorted out of order:

OrderedDict([
    (datetime.date(2021, 10, 1), {'net': -33924, 'entries': [{'text': 'Applied to 102101', 'amount': -16962, 'mode': 'debit'}, {'text': 'Applied to 102104', 'amount': -16962, 'mode': 'debit'}]}),
    (datetime.date(2021, 11, 3), {'net': -96118, 'entries': [{'text': 'Applied to 102104', 'amount': -96118, 'mode': 'debit'}]}), 
    (datetime.date(2021, 9, 24), {'net': 18000.0, 'entries': [{'text': 'Payment Received', 'amount': 18000.0, 'mode': 'credit'}]})
])

What are the caveats that I am missing here?


Solution

  • If you want to sort in some way that is not chronological, you can access the attributes you want to sort by and use tuple sorting:

    sorted(datetimes, key=lambda d: (d.month, d.seconds))  # or some other weird sorting
    

    If it's just a chronological sort however, then you don't need to bother with any of this:

    In [3]: OrderedDict(sorted(ledger.items()))
    Out[3]:
    OrderedDict([(datetime.date(2021, 9, 24),
                  {'net': 18000.0,
                   'entries': [{'text': 'Payment Received',
                     'amount': 18000.0,
                     'mode': 'credit'}]}),
                 (datetime.date(2021, 10, 1),
                  {'net': -33924,
                   'entries': [{'text': 'Applied to 102101',
                     'amount': -16962,
                     'mode': 'debit'},
                    {'text': 'Applied to 102104',
                     'amount': -16962,
                     'mode': 'debit'}]}),
                 (datetime.date(2021, 11, 3),
                  {'net': -96118,
                   'entries': [{'text': 'Applied to 102104',
                     'amount': -96118,
                     'mode': 'debit'}]})])