#python #list #performance
#python #Список #Производительность
Вопрос:
У меня есть список со значениями и список с некоторыми заданными числами:
my_list = [1, 3, 5, 6, 8, 10]
my_numbers = [2, 3, 4]
Теперь я хочу знать my_numbers
, существуют ли значения в my_list
и, если да, поместите соответствующие значения в конец my_list
. Я могу сделать это, например, так:
for number in my_numbers:
if number in my_list:
my_list.remove(number)
my_list.append(number)
Особенности:
- Я могу быть уверен, что ни в одном из списков нет дубликатов из-за моей настройки программы.
- Порядок, в котором совпадающие числа
my_numbers
помещаются в конецmy_list
, не имеет значения.
Вопрос: Могу ли я сделать это более эффективно с точки зрения производительности?
Комментарии:
1. Извините, я не понимаю, что вы имеете в виду. Пример кода работает нормально. И я тоже не получаю -1 на свой вопрос, разве это не хорошо объяснено? И как я могу сделать это вместо этого?
2. @TomKarzes Список
my_list
не повторяется. Существует толькоin
проверка для этого списка на каждой итерации цикла по другому списку,my_numbers
, поэтому модификация безопасна (даже если она не очень хороша с точки зрения производительности).3. @Frank, мой вопрос в том, есть ли более эффективный способ, у вас есть предложения? 🙂
4. Вы хотите отсортировать свой список на основе того, существует ли значение в другом списке? Затем вы можете отсортировать его на основе этого критерия:
my_numbers.sort(key=lambda i: i in my_list)
(возможноreversed=True
, я никогда не могу вспомнить, каким образом это будет сортировать …). Вы можете сделать это более эффективным, создавmy_list
set
. Это было бы разумным компромиссом между эффективностью и выразительностью. Вероятно, вы можете придумать еще более эффективные алгоритмы, но на этом этапе возникает вопрос, стоит ли это того.5. @Frank Ой, ты прав, спасибо.
Ответ №1:
Одно из возможных решений таково: перестроить список my_list
из двух частей:
- элементы, которых нет в
my_numbers
- элементы, которые находятся в
my_numbers
Обратите внимание, что я бы предложил использовать a set
для поиска. Тест на членство для a set
равен O(1)
(постоянное время), тогда как такой тест для a list
равен O(n)
, где n
длина списка.
Это означает, что общее время выполнения приведенного ниже кода равно O(max(m,n))
, где m, n — длины списков. Ваше первоначальное решение было больше похоже O(m*n)
на, что намного медленнее, если любой из списков большой.
my_numbers_set = set(my_numbers)
my_list = [x for x in my_list if x not in my_numbers_set]
[x for x in my_list if x in my_numbers_set]
Комментарии:
1. Спасибо, это действительно быстрее, чем удалить и поместить в конец существующего списка? Мне кажется, что изменение существующего списка происходит быстрее, чем создание 2 новых списков и объединение их вместе 🙂
2. Нет, это не так, потому что удаление элемента из списка занимает O (n) времени, если элемент находится где-то посередине. Обратите внимание, что все элементы за удаленным элементом необходимо переместить на одну позицию вперед. Это может быть реальной проблемой, если часто выполнять для длинных списков.
3. Понятно, спасибо за ответ. Я попробую и посмотрю, ускорит ли мой код