0

I have a simple dictionary and a list which i would like to sort by the values in my dictionary.

data_dict = {'foo' : 'one', 'bar' : 'two', 'foobar' : 'three', 'notinsort' : 'four'}

custom_sort = ['three','one','two'] 

my own attempt has been to use a dictionary comprehension with a custom key in the sort:

{k:v for k,v in sorted(data_dict.items(), key=lambda i : custom_sort.index(i[1]) )}

which will rightly return a ValueError: 'four' is not in list

no problem, I can filter this out with an if-else statement within the lambda? as I still want the values to be sorted initially by my custom sort then a natural sort will do.

{
    k: v
    for k, v in sorted(
        data_dict.items(),
        key=lambda i: custom_sort.index(i[1])
        if [k for k in data_dict.values() if k in custom_sort] 
        else sorted(data_dict.items()),
    )
}

this returns the same ValueError, any variations I've tried on this will end up giving me a natural sort ignoring my custom key.

my desired output from the input above is :

data_dict = {'foobar' : 'three', 'foo' : 'one', 'bar' : 'two', 'notinsort' : 'four'}

I've had a the following questions :

How do I sort a dictionary by value? & Custom Sorting Python Dictionary

but wasn't able to come to an answer.

Umar.H
  • 22,559
  • 7
  • 39
  • 74
  • What do you want the output of this sort to look like, taking into account a value not in the sort list (i.e. `'four'`)? Should it be in the sorted output? If so, at the end? At the start? – PyPingu Jan 13 '20 at 14:24
  • @PyPingu would like to be naturally sorted after my own custom sort (as per my example), but if you could show both that would be very interesting - however understand if its not within the scope of this question. – Umar.H Jan 13 '20 at 14:26
  • 1
    I don't know what you mean by naturally sorted? Do you mean deafult output if you just called `sorted(dict.items())`? Because if so then I think yatu's answer is your solution – PyPingu Jan 13 '20 at 14:28
  • Apologies for my use of bad language, by natural I meant the default sort of the `sorted` method yes it does, thanks @PyPingu – Umar.H Jan 13 '20 at 14:37

1 Answers1

4

You could instead define a dictionary beforehand for the lookups (reducing the complexity to that of sorting, i.e O(n log n), since dictionary look-ups are O(1) ). This works for python 3.6> where dictionarie's order is mantained:

d = {v:k for k,v in enumerate(custom_sort)}
# {'three': 0, 'one': 1, 'two': 2}
dict(sorted(data_dict.items(), key=lambda x: d.get(x[1], float('inf'))))
# {'foobar': 'three', 'foo': 'one', 'bar': 'two', 'notinsort': 'four'}
yatu
  • 86,083
  • 12
  • 84
  • 139