5

I was reading this really helpful SO post on sorting dictionaries. One of the most popular answers suggests this:

sorted(dict1, key=dict1.get)

While this seems to work perfectly fine, I don't get the key=dict1.get part.

What exactly is get here and what does it do?

I am only familiar with using get('X') to extract X from a dictionary... And I couldn't find anything in the docs on dictionaries and stdtypes, so any pointers are much appreciated!

NB here is what they have to say about get(), or is this something entirely different? Thanks!

get(key[, default]) Return the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError

Community
  • 1
  • 1
patrick
  • 4,455
  • 6
  • 44
  • 61
  • 2
    What is confusing you? You evidently know what `.get` invoked on a dictionary does, that's what's being called for each key in the dictionary. – jonrsharpe Sep 14 '16 at 17:08
  • 3
    best way to understand is to fire up a terminal, and test it yourself – danidee Sep 14 '16 at 17:09
  • 1
    If you've read up on `sorted` (with its `key` argument) and `dict.get`, I don't know what else is left to explain. – TigerhawkT3 Sep 14 '16 at 17:14
  • on top of the doc for `get`, consider reading the doc for `sorted`, and while you are at it, why not look at the doc for the parameter `key` of the `sorted` function? – njzk2 Sep 14 '16 at 17:14
  • 1
    Perhaps you're confused by the way a function is being passed as an argument to another function instead of being explicitly called? – TigerhawkT3 Sep 14 '16 at 17:17
  • thanks guys, zvone's&Moses's answers & reading the documentation on what `key` does really helped. It still looks weird to me, but I guess I just had never encountered that kind of function --> function as @TigerhawkT3 pointed out. Thanks for your help! – patrick Sep 14 '16 at 17:57

4 Answers4

14

The key argument to sorted is a callable (e.g. a function) which takes one argument.

By default, sorted sorts the values by comparing them to each other. For example:

sorted([2, 3, 1])   # returns [1, 2, 3]

This is because 1 < 2 < 3.

On the other hand, if a different value should be used for comparison, that can be defined with key. For example, to sort strings by length, one coudld do:

def string_length(s):
    return len(s)

sorted(['abcd', 'efghi', 'jk'], key=string_length)  # returns ['jk', 'abcd', 'efghi']

This is because string_length('jk') < string_length('abcd') < string_length('efghi').

But instead of a funcion, you can pass any other callable. In your example, that is dict1.get, so for each key in the dict, dict1.get(key) will be executed and the result of that will be used in comparison.

dict1 = {'a':3, 'b':1, 'c':2}

sorted(dict1, key=dict1.get) # returns ['b', 'c', 'a']

This is because dict1.get('b') < dict1.get('c') < dict1.get('a').

zvone
  • 18,045
  • 3
  • 49
  • 77
  • Just to simplify your "sort by length" a bit you could use `key=len`. :-) Or was that wrapper function intentional? – MSeifert Sep 14 '16 at 17:47
  • @MSeifert Yes, I just wanted it to be more understandable, so I created a new function, but of course `key=len` would do the same faster, with less code and in fact more readable (if you know how these things work). – zvone Sep 14 '16 at 18:48
5
sorted(dict1, key=dict1.get)

is a less verbose and more pythonic way of saying:

sorted(dict1, key=lambda x: dict1[x] if x in dict1 else None)

Bear in mind that iterating on a dictionary will return its keys, therefore the get method takes arguments which are the dictionary keys, which in turn returns the value that key is pointing to.

TL;DR It's a simple way of saying sort the dictionary keys using the values as the sort criteria.

Moses Koledoye
  • 77,341
  • 8
  • 133
  • 139
2

As you have found, get just gets the value corresponding to a given key. sorted will iterate through the iterable it's passed. In this case that iterable is a dict, and iterating through a dict just iterates through its keys. If you want to sort based on the values instead, you need to transform the keys to their corresponding values, and of course the obvious way to do this is with get.

To clarify, this is for if you want a list of keys sorted based on their values. If you just wanted a sorted list of values you could do sorted(dict1.values()), and if you wanted the keys sorted by their value (not the value they map to), you could just do sorted(dict1).

Example:

>>> d = {'a': 3, 'b': 2, 'c': 1}
>>> sorted(d)
['a', 'b', 'c']
>>> sorted(d.values())
[1, 2, 3]
>>> sorted(d, key=d.get)
['c', 'b', 'a']
spruceb
  • 621
  • 5
  • 12
1

the second parameter of sorted([dictionnary],[function]) is a function and not a value:

This means the method will compare the keys according to the value returned by the function applied to the items.

the parenthesis added after a function call mean you are passing a value, while without the parenthesis you pass the function

dict.get(x) is the value of the key x in dict

dict.get is the function that gets the said value from dict1

supposing we have

d = {'a': 3, 'b': 2, 'c': 1}

sorted(d) will compare 'a','b'and 'c' while sorted(d,d.get) will compare d.get('a'),d.get('b') and d.get('c')

Adalcar
  • 1,458
  • 11
  • 26