reordering list of dicts arbitrarily in python

I have a list of 4 dicts (always 4) that look something like this:

[{'id':'1','name':'alfa'},{'id':'2','name':'bravo'},{'id':'3','name':'charlie'},{'id':'4','name':'delta'}]

I know exactly the order I want them in, which is:

2, 3, 1, 4

what's the simplest way of reordering them?

Answers


If it's always four, and you always know the order, just simply like this:

lst = [{...},{...},{...},{...}]
ordered = [lst[1],lst[2],lst[0],lst[3]]

If you meant to sort them by 'id', in that order:

ordered = sorted(lst, key=lambda d: [2,3,1,4].index(int(d['id'])))

Note that index() is O(n) but doesn't require you to build a dictionary. So for small inputs, this may actually be faster. In your case, there are four elements, ten comparisons are guaranteed. Using timeit, this snippet runs 10% faster than the dictionary based solution by tokland... but it doesn't really matter since neither will likely be significant.


Here's a pretty general function to impose a wanted order (any key value not in the wanted order is placed at the end of the resulting list, in arbitrary sub-order):

def ordered(somelist, wantedorder, keyfunction):
    orderdict = dict((y, x) for x, y in enumerate(wantedorder))
    later = len(orderdict)
    def key(item):
        return orderdict.get(keyfunction(item), later)
    return sorted(somelist, key=key)

You'd be using it as

import operator
sortedlist = ordered(dictlist, ('2', '3', '1', '4'),
                     operator.itemgetter('id'))

A non-generalized solution:

lst = [{'id':'1','name':'alfa'},{'id':'2','name':'bravo'},{'id':'3','name':'charlie'},{'id':'4','name':'delta'}]
order = ["2", "3", "1", "4"]
indexes = dict((idfield, index) for (index, idfield) in enumerate(order))
print sorted(lst, key=lambda d: indexes[d["id"]])
# [{'id': '2', 'name': 'bravo'}, {'id': '3', 'name': 'charlie'}, {'id': '1', 'name': 'alfa'}, {'id': '4', 'name': 'delta'}]

And here generalized:

def my_ordered(it, wanted_order, key):
    indexes = dict((value, index) for (index, value) in enumerate(wanted_order))
    return sorted(it, key=lambda x: indexes[key(x)])

import operator  
print my_ordered(lst, order, operator.itemgetter("id"))

the_list.sort(key=lambda x: (3, 1, 2, 4)[int(x["id"])-1])
Update0

A new much simpler answer

the_list = [the_list[i - 1] for i in (2, 3, 1, 4)]

This way the OP can see his desired ordering, and there's no silliness with sorting, which is not required here. It's probably fast too.


If you want to re-order without regard for content of the dicts:

>>> order = 2, 3, 1, 4
>>> d = [{'id':'1','name':'alfa'},{'id':'2','name':'bravo'},{'id':'3','name':'charlie'},{'id':'4','name':'delta'}]
>>> index = dict(enumerate(dd))
>>> [index[i-1] for i in order]
[{'id': '2', 'name': 'bravo'}, {'id': '3', 'name': 'charlie'}, {'id': '1', 'name': 'alfa'}, {'id': '4', 'name': 'delta'}]

If you want to base your sorting on the 'id' of the dicts:

>>> sorted(d, key=lambda x: order.index(int(x['id'])))
[{'id': '2', 'name': 'bravo'}, {'id': '3', 'name': 'charlie'}, {'id': '1', 'name': 'alfa'}, {'id': '4', 'name': 'delta'}]

Need Your Help

working on django development server but not on apache

python django apache url

i am facing an issue with the apache server, we have written the code, in which if the url entered in the form field is valid it will display an error message, when i run the code through django