Допустим, у меня есть два списка, l1
и l2
. Я хочу выполнить l1 - l2
, который возвращает все элементы l1
не в l2
.
Я могу думать о подходе наивного цикла, но это будет действительно неэффективно. Каков питонный и эффективный способ сделать это?
В качестве примера, если у меня есть l1 = [1,2,6,8] and l2 = [2,3,5,8]
, l1 - l2
должен вернуться[1,6]
Ответы:
В Python есть языковая функция, называемая списками, которая идеально подходит для того, чтобы сделать подобные вещи чрезвычайно простыми. Следующий оператор делает именно то, что вы хотите, и сохраняет результат в
l3
:l3
будет содержать[1, 6]
.источник
in
оператор не так эффективен в списке.in
в списке O (n), аin
в множестве O (1). Тем не менее, пока вы не получите тысячи или более элементов, вы вряд ли заметите разницу.l3 = [x for x in l1 if x not in set(l2)]
? Уверен, еслиset(l2)
бы позвонили не раз.l2s = set(l2)
и затем сказатьl3 = [x for x in l1 if x not in l2s]
. Чуть проще.Одним из способов является использование наборов:
источник
l1
, что может быть нежелательным побочным эффектом.timeit.timeit('a = [1,2,3,4]; b = [1,3]; c = [i for i in a if a not in b]', number=100000) -> 0.12061533199999985
timeit.timeit('a = {1,2,3,4}; b = {1,3}; c = a - b', number=100000) -> 0.04106225999998969
. Поэтому, если производительность является значительным фактором, этот ответ может быть более уместным (а также, если вам неВ качестве альтернативы вы также можете использовать
filter
лямбда-выражение для получения желаемого результата. Например:Сравнение производительности
Здесь я сравниваю эффективность всех ответов, упомянутых здесь. Как и ожидалось, операция на
set
базе Arkku является самой быстрой.Разница в наборе Арку - первая (0,124 мкс за цикл)
Понимание списка Даниэля Придена с
set
поиском - Второе (0,302 мксек за цикл)Понятие списка пончиков в простом списке - третье (0,552 мкс за цикл)
Использование
filter
Мойнуддина Квадри - Четвертое (0,972 чел. За цикл)Акшай Хазари использует комбинацию
reduce
+filter
- Пятое (3,97 юсек за цикл)PS:
set
не поддерживает порядок и удаляет дубликаты элементов из списка. Следовательно, не используйте набор разностей, если вам нужно что-то из этого.источник
Расширяя ответ Donut и другие ответы здесь, вы можете получить еще лучшие результаты, используя понимание генератора вместо понимания списка, и используя
set
структуру данных (так какin
оператор - O (n) в списке, но O (1) на съемочной площадке).Итак, вот функция, которая будет работать для вас:
Результатом будет итерация, которая будет лениво извлекать отфильтрованный список. Если вам нужен реальный объект списка (например, если вам нужно сделать
len()
результат для результата), то вы можете легко построить список следующим образом:источник
Используйте тип набора Python. Это было бы самым Pythonic. :)
Кроме того, поскольку он является нативным, он также должен быть наиболее оптимизированным.
Видеть:
http://docs.python.org/library/stdtypes.html#set
http://docs.python.org/library/sets.htm (для старых питонов)
источник
l1
содержит повторяющиеся элементы.используйте Set Comppresions {x для x в l2} или set (l2), чтобы получить set, затем используйте List Compreatsions, чтобы получить список
тестовый код:
Результат теста производительности:
источник
l2set = set( l2 )
вместоl2set = { x for x in l2 }
Альтернативное решение:
источник