Sorting dictionary keys by values in a list?

Question:

I have a dictionary and a list. The values of the keys match those of the list, I’m just trying to find out how to sort the values in the dictionary by the values in the list.

>>> l = [1, 2, 37, 32, 4, 3]
>>> d = {
    32: 'Megumi', 
    1: 'Ai',
    2: 'Risa',
    3: 'Eri', 
    4: 'Sayumi', 
    37: 'Mai'
}

I’ve tried using something along the lines of…

>>> sorted(dict.keys(), key=list.index)

… but obviously that only returns the keys in the desired order.

(Should have realized at 3AM that list and dict were horrible names, I changed them to l and d accordingly.)

Asked By: Bryan Veloso

||

Answers:

You can’t sort a dictionary because a dictionary is not ordered.

What you can do instead is:

  • Get all the key-value pairs out of the dictionary, sort them and put them into a list or
  • What you are already doing: keep a sorted list of the keys and use the dictionary when you need the value corresponding to a key.
Answered By: Mark Byers

Don’t shadow the builtins dict and list

>>> L = [1, 2, 37, 32, 4, 3]
>>> D = {
...     32: 'Megumi',
...     1: 'Ai',
...     2: 'Risa',
...     3: 'Eri',
...     4: 'Sayumi',
...     37: 'Mai'
... }

# Seems roundabout to use sorted here
# This causes an index error for keys in D that are not listed in L
>>> sorted(D.items(), key=lambda x:L.index(x[0]))
[(1, 'Ai'), (2, 'Risa'), (37, 'Mai'), (32, 'Megumi'), (4, 'Sayumi'), (3, 'Eri')]
>>>

# I think this is more direct than using sorted.
# This also ignores/skips keys in D that aren't listed in L
>>> [(i,D[i]) for i in L]
[(1, 'Ai'), (2, 'Risa'), (37, 'Mai'), (32, 'Megumi'), (4, 'Sayumi'), (3, 'Eri')]
>>>
Answered By: John La Rooy

Sorted dict is in fact a list of 2-tuples, because in Python 2.x there’re no ordered dictionaty built-in. You almost got the solution, just add a value lookup after sorting keys:

[(k,dict[k]) for k in sorted(dict.keys(), key=list.index)]

But this fails when a key is not in list. Let’s add a modification to put all such values at the end of sort, ordered by value:

def _index(x): # Allow non-full key list to be used in sorting
    try: return (list.index(x), x)
    except ValueError: return (sys.maxint, x)

[(k,dict[k]) for k in sorted(dict.keys(), key=_index)]
Answered By: Alexander Lebedev

You shouldn’t call you variables dict and list, because then, you cant use the build-in methods any more. I have renamed them in this example.

>>> l = [1, 2, 37, 32, 4]
>>> d = dict = {
...     32: 'Megumi', 
...     1: 'Ai',
...     2: 'Risa',
...     3: 'Eri', 
...     4: 'Sayumi', 
...     37: 'Mai'
... }

Note that prior to Python 3.7 you could not sort dictionaries in Python (they were hash tables sorted by the hash functions of the keys). Alternative dictionary implementations existed to work around this (OrderedDict).

But you can create a new list containing the (key, value)-tuples from any dictionary, which is sorted by the first list:

>>> s = list((i, d.get(i)) for i in L)
>>> print s
[(1, 'Ai'), (2, 'Risa'), (37, 'Mai'), (32, 'Megumi'), (4, 'Sayumi')]

Or if you are only interested in the values:

>>> s = list(d.get(i) for i in L)
>>> print s
['Ai', 'Risa', 'Mai', 'Megumi', 'Sayumi']

Hope that helps!

Answered By: tux21b

In Python 3.1, you could use the OrderedDict class:

from collections import OrderedDict

l = [1, 2, 37, 32, 4]
d = {
    32: 'Megumi', 
    1: 'Ai',
    2: 'Risa',
    3: 'Eri', 
    4: 'Sayumi', 
    37: 'Mai'
}

def myindex(element):
    try:
        return l.index(element)
    except ValueError:
        return -1 # nonexisting keys are appended to the beginning of the list

od = OrderedDict(sorted(d.items(), key = lambda t: myindex(t[0])))

print(od)

As I didn’t know what you want to do with keys that aren’t in the list, I just return -1 in that case, meaning those elements are prepended to the list somehow (i.e. in non-stable order).

My example will print

OrderedDict([(3, 'Eri'), (1, 'Ai'), (2, 'Risa'), (37, 'Mai'), (32, 'Megumi'), (4, 'Sayumi')])
Answered By: AndiDog
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.