2

I just want to sort the dictionary by the values but little different way.

Here is my dictionary

issues = {
    1: {'title': 'Title 1','level': 'low'}, 
    2: {'title': 'Title 2','level': 'medium'}, 
    3: {'title': 'Title 3','level': 'high'}, 
    4: {'title': 'Title 4','level': 'low'}, 
    5: {'title': 'Title 5','level': 'medium'}, 
    6: {'title': 'Title 6','level': 'high'}
}

I want to sort the above issues by its level (low, medium, high).

sorted_issues = {
    1: {'title': 'Title 1','level': 'low'}, 
    4: {'title': 'Title 4','level': 'low'}, 
    2: {'title': 'Title 2','level': 'medium'}, 
    5: {'title': 'Title 5','level': 'medium'}, 
    3: {'title': 'Title 3','level': 'high'}, 
    6: {'title': 'Title 6','level': 'high'}
}

I got many examples but all those had only one value in the value section. But here values are not single value its dictionary

Thanks in advance.

Sathish
  • 1,481
  • 5
  • 20
  • 33
  • 1
    sorting dictionaries does not make sense. if you needed an ordered data structure go with something else – Ma0 Jun 26 '20 at 07:35
  • 3
    Does this answer your question? [How do I sort a dictionary by value?](https://stackoverflow.com/questions/613183/how-do-i-sort-a-dictionary-by-value) – Narendra Prasath Jun 26 '20 at 07:48
  • 3
    @MaO Python dicts are formally ordered since 3.7, informally so since 3.6, and obviously OrderedDict has been there for a long, long time. – Masklinn Jun 26 '20 at 07:48

8 Answers8

3

You can do this

from collections import OrderedDict
issues = {
    1: {'title': 'Title 1','level': 'low'},
    2: {'title': 'Title 2','level': 'medium'},
    3: {'title': 'Title 3','level': 'high'},
    4: {'title': 'Title 4','level': 'low'},
    5: {'title': 'Title 5','level': 'medium'},
    6: {'title': 'Title 6','level': 'high'}
}
priorities = {
    'low': 1,
    'medium': 2,
    'high': 3
}
x = OrderedDict(sorted(issues.items(), key = lambda item: priorities[item[1]['level']]))
for key, value in x.items():
    print(f"{key}, {value}")
'''
1, {'title': 'Title 1', 'level': 'low'}
4, {'title': 'Title 4', 'level': 'low'}
2, {'title': 'Title 2', 'level': 'medium'}
5, {'title': 'Title 5', 'level': 'medium'}
3, {'title': 'Title 3', 'level': 'high'}
6, {'title': 'Title 6', 'level': 'high'}
'''
print(x)
'''
OrderedDict([(1, {'title': 'Title 1', 'level': 'low'}), (4, {'title': 'Title 4', 'level': 'low'}), (2, {'title': 'Title 2', 'level': 'medium'}), (5, {'title': 'Title 5', 'level': 'medium'}), (3, {'title': 'Title 3', 'level': 'high'}), (6, {'title': 'Title 6', 'level': 'high'})])
'''
Pani
  • 1,317
  • 1
  • 14
  • 20
2

Dictionaries mantain insertion order for pythons 3.7>, otherwise you have OrderedDict. To sort the dictionaries in such way, you'll need to define a lookup table to rank the level field, and then sort using tuples (level_lookup, title) (assuming you also need to sort by title, otherwise only the first term is necessary).

Also note that you'll need to cast the numerical part in title to integer, otherwise the sorting will be lexicographic, which implies that 9 > 10:

mapper = {'low':0, 'medium':1, 'high':2}
dict(sorted(issues.items(), key=lambda x: (mapper[x[1]['level']], 
                                           int(x[1]['title'].rsplit(maxsplit=1)[1]))))

{1: {'title': 'Title 1', 'level': 'low'},
 4: {'title': 'Title 4', 'level': 'low'},
 2: {'title': 'Title 2', 'level': 'medium'},
 5: {'title': 'Title 5', 'level': 'medium'},
 3: {'title': 'Title 3', 'level': 'high'},
 6: {'title': 'Title 6', 'level': 'high'}}

If further sorting by the title isn't necessary, you only need:

dict(sorted(issues.items(), key=lambda x: mapper[x[1]['level']]))
yatu
  • 86,083
  • 12
  • 84
  • 139
1

Even without maintaining the order of input we can write a custom function for sorting based on the keys or labels provided (level in your case),

import pprint
issues = {
    1: {'title': 'Title 1','level': 'low'}, 
    2: {'title': 'Title 2','level': 'medium'}, 
    3: {'title': 'Title 3','level': 'high'}, 
    4: {'title': 'Title 4','level': 'low'}, 
    5: {'title': 'Title 5','level': 'medium'}, 
    6: {'title': 'Title 6','level': 'high'}
}

def customSort(data, labels):
    temp = {}
    inx = 0
    for label in labels:
        for k,v in data.items():
            if v["level"] == label:
                inx += 1
                temp[inx] = v.copy()
    return temp

labels = ["low","medium","high"]
issues_sorted = customSort(issues,labels)
pprint.pprint(issues_sorted)

Output:

{1: {'level': 'low', 'title': 'Title 1'},
 2: {'level': 'low', 'title': 'Title 4'},
 3: {'level': 'medium', 'title': 'Title 2'},
 4: {'level': 'medium', 'title': 'Title 5'},
 5: {'level': 'high', 'title': 'Title 3'},
 6: {'level': 'high', 'title': 'Title 6'}}
Shyam Mittal
  • 188
  • 2
  • 9
0

Since Python version 3.7 dicts keep the insertion order of your elements. In previous versions of python this was not the case.

Therefore you can order the items, sort them depending on your criteria and insert them afterwards in a (new) dict.

Or use OrderedDict:

import collections

def custom_sort(item):
    prio = ['low', 'medium', 'high']
    return prio.index(item[-1]["level"])

issues = {
    1: {'title': 'Title 1','level': 'low'},
    2: {'title': 'Title 2','level': 'medium'},
    3: {'title': 'Title 3','level': 'high'},
    4: {'title': 'Title 4','level': 'low'},
    5: {'title': 'Title 5','level': 'medium'},
    6: {'title': 'Title 6','level': 'high'}
}

res = collections.OrderedDict(sorted(issues.items(), key=custom_sort))
print(res)
Alexander Kosik
  • 669
  • 3
  • 10
0

Please try the code below:

issues = {
        1: {'title': 'Title 1','level': 'low'}, 
        2: {'title': 'Title 2','level': 'medium'}, 
        3: {'title': 'Title 3','level': 'high'}, 
        4: {'title': 'Title 4','level': 'low'}, 
        5: {'title': 'Title 5','level': 'medium'}, 
        6: {'title': 'Title 6','level': 'high'}
    }
sortlist=['low','medium','high']
    
sorted_issues={k: v for k, v in sorted(issues.items(), key=lambda item: sortlist.index(item[1]['level']))}
print(sorted_issues)

Output:

{1: {'title': 'Title 1', 'level': 'low'}, 
4: {'title': 'Title 4', 'level': 'low'}, 
2: {'title': 'Title 2', 'level': 'medium'}, 
5: {'title': 'Title 5', 'level': 'medium'}, 
3: {'title': 'Title 3', 'level': 'high'}, 
6: {'title': 'Title 6', 'level': 'high'}}
Roohollah Etemadi
  • 1,243
  • 1
  • 6
  • 18
0

This is a bit of a hack since the last letters of 'low', 'medium', and 'high' have a rather unintentional alphabetized order. But a one liner non the less:

sorted_issues = {k: v for k, v in  sorted(issues.items(), key=lambda kv: kv[1]['level'][-1], reverse=True)}
Eugene Upston
  • 196
  • 1
  • 3
0

You can try

issues = {
    1: {'title': 'Title 1','level': 'low'},
    2: {'title': 'Title 2','level': 'medium'},
    3: {'title': 'Title 3','level': 'high'},
    4: {'title': 'Title 4','level': 'low'},
    5: {'title': 'Title 5','level': 'medium'},
    6: {'title': 'Title 6','level': 'high'}
}

levels_priorty = ['low', 'medium', 'high']
res = dict(sorted(issues.items(), key=lambda x: [levels_priorty.index(x[1]['level']), int(x[1]['title'].replace("Title ", ""))]))
print(res)

Output

{1: {'title': 'Title 1', 'level': 'low'}, 
4: {'title': 'Title 4', 'level': 'low'}, 
2: {'title': 'Title 2', 'level': 'medium'}, 
5: {'title': 'Title 5', 'level': 'medium'}, 
3: {'title': 'Title 3', 'level': 'high'}, 
6: {'title': 'Title 6', 'level': 'high'}}
Leo Arad
  • 4,452
  • 2
  • 6
  • 17
0

This can easily be achieved without importing or or installing additional modules in just a few short lines of code.

Because below python 3.1 dictionaries can't remember their order. https://docs.python.org/3.1/whatsnew/3.1.html

You can simply order this dict like this:

issues = {
            1: {'title': 'Title 1','level': 'low'}, 
            2: {'title': 'Title 2','level': 'medium'}, 
            3: {'title': 'Title 3','level': 'high'}, 
            4: {'title': 'Title 4','level': 'low'}, 
            5: {'title': 'Title 5','level': 'medium'}, 
            6: {'title': 'Title 6','level': 'high'}
        }


# CONVERT THE issues DICTIONARY INTO A LIST
issues_list = [{k: v} for k, v in issues.items()]

# A FUNCTION THAT SELECTS THE SORTING ELEMENT 
level = lambda issue: issue.items()[0][1]['level']

# WE USE THIS DICTIONARY TO CONVERT THE SORTING ELEMENT INTO A NUMBER
levels = {'low':1, 'medium':2, 'high':3}

# A FUNCTION THAT RETURNS A NUMBER TO BE SORTED BY THE SORT FUNCTION
dict_element = lambda d: levels[level(d)]

# NOW SORT THE LIST BASED ON LEVEL
issues_list.sort(key=dict_element)

# PRINT SORTED LIST
for i in issues_list:
    print i


# RESULT
# {1: {'level': 'low', 'title': 'Title 1'}}
# {4: {'level': 'low', 'title': 'Title 4'}}
# {2: {'level': 'medium', 'title': 'Title 2'}}
# {5: {'level': 'medium', 'title': 'Title 5'}}
# {3: {'level': 'high', 'title': 'Title 3'}}
# {6: {'level': 'high', 'title': 'Title 6'}} 
Diego Suarez
  • 901
  • 13
  • 16