Сортировка списка диктов в python, использование другого списка в качестве «фильтра»? - PullRequest
2 голосов
/ 14 июля 2011
b = [{'id': 'a'}, {'id': 'c'}, {'id': 'b'}, {'id': 'e'}]

Мне нужно, чтобы это стало:

b = [{'id': 'a'}, {'id': 'c'}, {'id': 'e'}, {'id': 'b'}]

Этот новый порядок определяется другим списком.

my_filter = ['a', 'c', 'e', 'b']

... как выКак видите, список с dicts теперь имеет последовательность идентификаторов, которые были представлены в переменной my_filter.

Я могу переупорядочить это, но используя несколько форсов, и это не будет эффективным.Ты знаешь лучший способ?Я уже знаю, как сортировать список словарей по значениям словаря , но мне нужно, чтобы этот порядок определялся другим списком.

EDIT : my_filter был назван filter, я изменился после рекомендации Дэйва Кирби , так как это встроенный.Поскольку в некоторых ответах по-прежнему содержится filter, этот раздел редактирования позволяет избежать путаницы, если в некоторых из них вы видите filter.

Ответы [ 5 ]

7 голосов
/ 14 июля 2011
>>> sorted(b, key=lambda x: filter.index(x['id']))
[{'id': 'a'}, {'id': 'c'}, {'id': 'e'}, {'id': 'b'}]
5 голосов
/ 14 июля 2011

Имейте в виду, что решение Игнасио эквивалентно выполнению вложенных циклов for, которых вы хотели избежать.то есть это п ^ 2.Более эффективное решение заключается в следующем:

>>> filterdict = dict((k,i) for i,k in enumerate(filter))
>>> sorted(b, key=lambda x: filterdict[x['id']])
[{'id': 'a'}, {'id': 'c'}, {'id': 'e'}, {'id': 'b'}]

или:

>>> b.sort(key=lambda x: filterdict[x['id']])
>>> b
[{'id': 'a'}, {'id': 'c'}, {'id': 'e'}, {'id': 'b'}]

для сортировки на месте.

Редактировать: antonakos 'Решение является лучшим (2n), если ваши идентификаторы уникальны (что, вероятно, является безопасным предположением, но вы не указали, поэтому я не хотел предполагать).Вот несколько более короткий способ написания того, что он написал, на случай, если это поможет прояснить ситуацию:

>>> d = dict((i['id'], i) for i in b)
>>> [d[key] for key in filter]
[{'id': 'a'}, {'id': 'c'}, {'id': 'e'}, {'id': 'b'}]
3 голосов
/ 14 июля 2011
order = dict((v, i) for (i,v) in enumerate(filter))
sorted(b, key=lambda x:order[x['id']])

Это должно быть несколько более эффективно, чем ответ Игнасио, поскольку поиск по словарю - O (1), а индекс (x) - O (n).

BTW-фильтр - это имя встроенной функции, поэтому не следует использовать его в качестве имени переменной.

3 голосов
/ 14 июля 2011

Создайте обратный словарь и найдите значения последовательности фильтров:

def order_by_values_for_key(key, dictionaries, values):
    rev = {}
    for d in dictionaries:
        val = d[key]
        rev[val] = d

    return [ rev[val] for val in values ]

b = [{'id': 'a'}, {'id': 'c'}, {'id': 'b'}, {'id': 'e'}]
filter = ['a', 'c', 'e', 'b']
print order_by_values_for_key('id', b, filter)

Используя словарь Python3, вы можете написать:

def order_by_values_for_key(key, dictionaries, values):
    rev = { d[key] : d for d in dictionaries }
    return [ rev[val] for val in values ]
1 голос
/ 14 июля 2011

Чтобы добавить к ответам антонакоса и Кейтера (мне не хватает представителя, чтобы комментировать напрямую), словарное понимание также доступно в 2.7, и было примерно на 1/3 быстрее для этого примера:

python -mtimeit "{k: i for i,k in enumerate(range(1000))}"
10000 loops, best of 3: 93.5 usec per loop

python -mtimeit "dict((k,i) for i,k in enumerate(range(1000)))"
10000 loops, best of 3: 158 usec per loop
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...