Сортировка списка объектов в соответствии со свойством в другом списке

#python #sorting

#python #сортировка

Вопрос:

Мои данные состоят из объектов с некоторым свойством ( pk ):

 obj0.pk = 'aa'
obj1.pk = 33
ojb2.pk = 'm0'
 

У меня есть куча неупорядоченных объектов:

 data = [obj0, obj1, obj2]
 

И у меня есть список pks, в которых указывается порядок упорядочения объектов:

 pks = [33, 'aa', 'm0']
 

Теперь я вызываю функцию для упорядочения данных:

 output = sort_data_by_pk(data, pks)
 

Ожидаемый результат:

 [obj1, obj0, obj2]
 

Как мы можем реализовать sort_data_by_pk на python?

Редактировать

Моя первоначальная реализация:

 def sort_data_by_pk(data, pks):
    lookup = {instance.pk: instance for instance in data}
    return [lookup[pk] for pk in pks]
 

Комментарии:

1. Какую версию Python вы используете? Потому [33, 'aa', 'm0'] что изначально сортируется только в 2.7 и ниже. Python 3 отказывается сравнивать строки с целыми числами, если вы не постараетесь указать, как это должно быть сделано.

2. Упс, я неправильно понял цель pks . Если этот список определяет общий порядок, тогда нет прямого сравнения между элементами.

3. Я был бы признателен, если downvoters объяснит свои причины …

4. @volingas Я не голосовал за понижение, но обычно люди голосуют за понижение всякий раз, когда вопрос публикуется без того, чтобы OP проявлял некоторые усилия при попытке реализации. Ваше редактирование теперь показывает, что вы сделали хорошую (на самом деле, отличную) попытку реализации, так что 1 вам.

Ответ №1:

Использование index метода в качестве ключевой функции излишне делает решение O (n ^ 2 log n), а не O (n log n) в средней сложности времени.

Вместо этого вы можете создать dict, который сопоставляет элементы с data их индексами, чтобы вы могли использовать dict для сопоставления атрибута объектов pk в качестве ключевой функции для порядка сортировки:

 order = {k: i for i, k in enumerate(pks)}
output = sorted(data, key=lambda o: order[o.pk])
 

Комментарии:

1. Это была моя первоначальная реализация, но создание дополнительного dict выглядело немного неуклюже

2. Если ваш размер data большой, то эффективность O (1) в поиске, которую приносит дополнительный dict, стоит дополнительной строки кода.

3. На самом деле, я понимаю, что моя реализация отличается. Я добавил это к своему вопросу. Видите ли вы какие-либо преимущества / недостатки по сравнению с вашей реализацией?

4. Да, ваша реализация намного лучше, поскольку она занимает всего O (n) по временной сложности. Я отвлекся на sorted функцию, используемую другими ответами, и забыл, что в вашем случае это можно просто сделать с помощью обратного поиска по индексу.

5. Спасибо, тогда я сохраню свой.

Ответ №2:

Вы могли sort data бы на основе index в pks подобном,

 >>> pks = [33, 'aa', 'm0']
>>> data = [ob0, ob1, ob2]
>>> 
>>> 
>>> sorted(data, key=lambda x: pks.index(x.pk))
[<__main__.Obj object at 0x7f03851cc290>, <__main__.Obj object at 0x7f03851cc250>, <__main__.Obj object at 0x7f03851cc2d0>]
 

Ответ №3:

Я думаю, вы хотите использовать sorted с лямбдой, которая получает индекс первичного ключа pks .

 sorted_data = sorted(data, lambda d: pks.index(d.pk))
 

Ответ №4:

Если ваши списки большие, вы можете сначала создать dict, чтобы избежать многократных вызовов «index» в списке.

 pks = [33, 'aa', 'm0']
data = [ob0, ob1, ob2]
d = { obj.pk: obj for obj in data } #lookup table for pks
sorted_list = [ d[pk] for pk in pks ] #create a new list out of list "pks" where pk is replaced by the value in the lookup table
 

Комментарии:

1. Да, это именно моя оригинальная реализация, которую я добавил к вопросу