Maxime
Maxime

Reputation: 634

Sort a dict based on numbered keys

I would like to sort a dict based on keys that have a pattern like "[0-9]+_[A-Z]+". I would like it to be ordered by ascending number.

Here is where I am for the moment :

import operator
myDict = {
        '120_str' : 'value',
        '150_str' : 'value',
        '110_str' : 'value',
        '80_str' : 'value',
        '10_str' : 'value',
        '20_str' : 'value'
        }

sortedDict = sorted(myDict.items(), key=operator.itemgetter(0))

What I actually have :

sortedDict = {
        '10_str' : 'value',
        '110_str' : 'value',
        '120_str' : 'value',
        '150_str' : 'value',
        '20_str' : 'value',
        '80_str' : 'value'
        }

What I would like to have :

sortedDict = {
        '10_str' : 'value',
        '20_str' : 'value',
        '80_str' : 'value',
        '110_str' : 'value',
        '120_str' : 'value',
        '150_str' : 'value'
        }

Upvotes: 1

Views: 64

Answers (5)

Asav Patel
Asav Patel

Reputation: 1162

how about this? you can filter digits from the string and sort your dictionary based on that.

this also doesn't require you to split using a particular character. just in case if your key structure changes this would still work.

sorted(myDict.items(), key=lambda t: int(filter(str.isdigit, t[0])))

Upvotes: 2

jpp
jpp

Reputation: 164693

Here is one way, assuming output is a list of tuples. Dictionaries are not considered to be ordered, although they may be in the future.

Sort after converting to int, then add back the string formatting:

myLst = [(str(k)+'_str', v) for k, v in \
         sorted([(int(k.split('_')[0]), v) for k, v in myDict.items()])]

# [('10_str', 'value'),
#  ('20_str', 'value'),
#  ('80_str', 'value'),
#  ('110_str', 'value'),
#  ('120_str', 'value'),
#  ('150_str', 'value')]

Upvotes: 1

Ajax1234
Ajax1234

Reputation: 71451

You can try this:

import re
sortedDict = {
    '10_str' : 'value',
    '110_str' : 'value',
    '120_str' : 'value',
    '150_str' : 'value',
    '20_str' : 'value',
    '80_str' : 'value'
    }

final_data = sorted(sortedDict.items(), key=lambda x:int(re.findall('^\d+', x[0])[0]))

Output:

[('10_str', 'value'), ('20_str', 'value'), ('80_str', 'value'), ('110_str', 'value'), ('120_str', 'value'), ('150_str', 'value')]

Upvotes: 1

wim
wim

Reputation: 362786

>>> def key(s):
...     n, s = s.split('_', 1)
...     return int(n), s
... 
>>> from collections import OrderedDict
>>> OrderedDict([(k, myDict[k]) for k in sorted(myDict, key=key)])
OrderedDict([('10_str', 'value'),
             ('20_str', 'value'),
             ('80_str', 'value'),
             ('110_str', 'value'),
             ('120_str', 'value'),
             ('150_str', 'value')])

Upvotes: 3

heemayl
heemayl

Reputation: 42017

Use _ separated first element (int) as the sorting key:

sorted(myDict.items(), key=lambda x: int(x[0].split('_')[0]))

Use collections.OrderedDict to maintain the ordering:

collections.OrderedDict(sorted(myDict.items(), key=lambda x: int(x[0].split('_')[0])))

Example:

In [109]: sorted(myDict.items(), key=lambda x: int(x[0].split('_')[0]))
Out[109]: 
[('10_str', 'value'),
 ('20_str', 'value'),
 ('80_str', 'value'),
 ('110_str', 'value'),
 ('120_str', 'value'),
 ('150_str', 'value')]

In [110]: collections.OrderedDict(sorted(myDict.items(), key=lambda x: int(x[0].split('_')[0])))
Out[110]: 
OrderedDict([('10_str', 'value'),
             ('20_str', 'value'),
             ('80_str', 'value'),
             ('110_str', 'value'),
             ('120_str', 'value'),
             ('150_str', 'value')])

Upvotes: 3

Related Questions