views:

221

answers:

5

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.)

+1  A: 

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.
Mark Byers
+5  A: 

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')]
>>>
gnibbler
A: 

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)]
Alex Lebedev
+4  A: 

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'
... }

You can't sort the default dict type in Python, because it's a hash table and therefore sorted by the hash functions of the keys. Anyway, you might find some alternative Python implementations when you search for OrderedDict or something like that in google.

But you can create a new list containing the (key, value)-tuples from the 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!

tux21b
Thank you! I ended up using your 2nd solution since I just realized I really didn't need the keys. :)
Bryan Veloso
A: 

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')])
AndiDog