views:

628

answers:

6

In Oracle sql there is a feature to order as follow:

order by decode("carrot" = 2
               ,"banana" = 1
               ,"apple" = 3)

What will be the best way to implement this in python?

I want to be able to order a dict on its keys. And that order isn't alphabetically or anything, I determine the order.

+2  A: 

Python's dict is a hashmap, so it has no order. But you can sort the keys separately, extracting them from the dictionary with keys() method.

sorted() takes comparison and key functions as arguments.

You can do exact copy of your decode with

sortedKeys = sorted(dictionary, {"carrot": 2
                                ,"banana": 1
                                ,"apple":  3}.get);
vartec
Won't sorted(dictionary, lambda etc...) work just as well? I don't think you have to explicitly extract the keys, sorted will do this for you?
Tomislav Mutak
No. As I've said, dictionaries have no order. dictionary.keys() is list, thus can be ordered.
vartec
-1: Nice answer right up until the lambda. Then, not so nice.
S.Lott
Who said anything about dictionaries having order? All I said was that sorted(d) is the equivalent of sorted(d.keys()) if d is a dictionary. Try it for yourself (this is Python 2.4.4):>>> d = {2:"a", 1:"b"}>>> sorted(d)[1, 2]>>> sorted(d.keys())[1, 2]
Tomislav Mutak
@S.Lott: there, no lambda ;-)
vartec
@Tomislav: ok, didn't know about that feature. updated.
vartec
+2  A: 

You can't sort a dictionary; a dictionary is a mapping and a mapping has no ordering.

You could extract the keys and sort those, however:

keys = myDict.keys()
sorted_keys = sorted(keys, myCompare)
Paolo Bergantino
+1  A: 

A dict is not ordered. You will need to keep a list of keys.

You can pass your own comparison function to list.sort() or sorted().

If you need to sort on multiple keys, just concatenate them in a tuple, and sort on the tuple.

Joe Koberg
+8  A: 

Use the key named keyword argument of sorted().

#set up the order you want the keys to appear here
order = ["banana", "carrot", "apple"]

# this uses the order list to sort the actual keys.
sorted(keys, key=order.index)

For higher performance than list.index, you could use dict.get instead.

#this builds a dictionary to lookup the desired ordering
order = dict((key, idx) for idx, key in enumerate(["banana", "carrot", "apple"]))

# this uses the order dict to sort the actual keys.
sorted(keys, key=order.get)
recursive
+1: With the 'cmp' argument begin removed in Python 3.0, and comparison functions being horribly slow anyway, using the key argument like this is indeed the best way to proceed
Jarret Hardie
That's pretty elegant. I like that.
SpoonMeiser
+1  A: 

There will be OrderedDict in new Python versions: http://www.python.org/dev/peps/pep-0372/.

Meanwhile, you can try one of the alternative implementations: http://code.activestate.com/recipes/496761/, Ordered Dictionary.

Eugene Morozov
+3  A: 

You can't order a dict per se, but you can convert it to a list of (key, value) tuples, and you can sort that.

You use the .items() method to do that. For example,

>>> {'a': 1, 'b': 2}
{'a': 1, 'b': 2}
>>> {'a': 1, 'b': 2}.items()
[('a', 1), ('b', 2)]

Most efficient way to sort that is to use a key function. using cmp is less efficient because it has to be called for every pair of items, where using key it only needs to be called once for every item. Just specify a callable that will transform the item according to how it should be sorted:

sorted(somedict.items(), key=lambda x: {'carrot': 2, 'banana': 1, 'apple':3}[x[0]])

The above defines a dict that specifies the custom order of the keys that you want, and the lambda returns that value for each key in the old dict.

ʞɔıu
cmp does not force a bubble sort, but it is slower.
recursive
"forces a it to do a bubble sort"? Really? I find that hard to believe.
S.Lott