переупорядочение списка диктов произвольно в python - PullRequest
4 голосов
/ 21 июля 2010

У меня есть список из 4 диктов (всегда 4), которые выглядят примерно так:

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

Я точно знаю, в каком порядке я хочу их получить:

2, 3, 1, 4

какой самый простой способ их переупорядочить?

Ответы [ 5 ]

4 голосов
/ 21 июля 2010

Если всегда четыре, и вы всегда знаете порядок, просто так:

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

Если вы хотите отсортировать их по 'id', в таком порядке:

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

Обратите внимание, что index() - это O(n), но не требует создания словаря.Так что для небольших входов это может быть быстрее.В вашем случае есть четыре элемента, десять сравнений гарантированы.При использовании timeit этот фрагмент работает на 10% быстрее, чем решение на основе словаря от tokland ... но это не имеет значения, поскольку ни один из них, вероятно, не будет существенным.

3 голосов
/ 21 июля 2010

Вот довольно общая функция для наложения требуемого порядка (любое значение ключа, не находящееся в требуемом порядке, помещается в конец результирующего списка в произвольном порядке):

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буду использовать его как

import operator
sortedlist = ordered(dictlist, ('2', '3', '1', '4'),
                     operator.itemgetter('id'))
2 голосов
/ 21 июля 2010

Необобщенное решение:

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

А здесь обобщенное:

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"))
2 голосов
/ 21 июля 2010
the_list.sort(key=lambda x: (3, 1, 2, 4)[int(x["id"])-1])

Update0

Новый, намного более простой ответ

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

Таким образом, ОП может видеть желаемый порядок, и нет глупости с сортировкой, которая здесь не требуется.Наверное, тоже быстро.

0 голосов
/ 21 июля 2010

Если вы хотите изменить порядок без учета содержания диктов:

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

Если вы хотите основывать свою сортировку на 'id' диктов:

>>> 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'}]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...