4 votes

réordonner une liste de dicts de façon arbitraire en python

J'ai une liste de 4 dicts (toujours 4) qui ressemble à quelque chose comme ceci :

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

Je sais exactement dans quel ordre je les veux, c'est-à-dire :

2, 3, 1, 4

quelle est la manière la plus simple de les réorganiser ?

4voto

Stephen Points 16714

Si c'est toujours quatre, et que vous connaissez toujours l'ordre, faites simplement comme ça :

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

Si vous voulez les trier par "id", dans cet ordre :

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

Notez que index() est O(n) mais ne vous oblige pas à construire un dictionnaire. Ainsi, pour les petites entrées, cela peut être plus rapide. Dans votre cas, il y a quatre éléments, dix comparaisons sont garanties. Utilisation de timeit cet extrait est 10% plus rapide que la solution basée sur le dictionnaire de tokland... mais cela n'a pas vraiment d'importance puisque ni l'un ni l'autre ne sera probablement significatif.

3voto

Alex Martelli Points 330805

Voici une fonction assez générale pour imposer un ordre souhaité (toute valeur de clé qui n'est pas dans l'ordre souhaité est placée à la fin de la liste résultante, dans un sous-ordre arbitraire) :

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)

Vous l'utiliseriez comme

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

2voto

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

Mise à jour 0

Une nouvelle réponse beaucoup plus simple

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

De cette façon, le PO peut voir l'ordre qu'il souhaite, et il n'y a pas de bêtises à faire avec le tri, qui n'est pas nécessaire ici. C'est probablement aussi plus rapide.

2voto

tokland Points 29813

Une solution non généralisée :

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

Et ici généralisé :

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

0voto

SilentGhost Points 79627

Si vous voulez réordonner sans tenir compte du contenu des 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'}]

Si vous voulez baser votre tri sur le 'id' des 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'}]

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X