Если значения существуют в списке, поместите их в конец списка в Python

#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. Понятно, спасибо за ответ. Я попробую и посмотрю, ускорит ли мой код