Как вычесть элементы одного списка из другого в python
Перейти к содержимому

Как вычесть элементы одного списка из другого в python

  • автор:

Какой самый простой способ вычесть все элементы одного списка из другого списка?

Кажется, сумма хорошо работает для двух списков, но вычитание не работает.

Для уточнения: Порядок не имеет значения. L2 — это подмножество L1. Дубликаты нужно сохранить. Поэтому нельзя использовать set .

>>> [1,2,2,3]+[1,2,3] [1, 2, 2, 3, 1, 2, 3] >>> [1,2,2,3]-[1,2] Traceback (most recent call last): File "", line 1, in TypeError: unsupported operand type(s) for -: 'list' and 'list' 

Поделиться Источник 26 декабря 2018 в 15:09

3 ответа

Вы можете попробовать использовать remove :

list1 = [1,2,2,2,3] list2 = [1,2,2] [list1.remove(i) for i in list2] list1 

Обновление без включения списка, используя стандартные циклы.

for i in list2: list1.remove(i) list1 

Поделиться 26 декабря 2018 в 15:21

Вот как я бы это сделал:

def remove_elems(l1, l2): removals = set(l2) result = [] for elem in l1: if elem in removals: removals.remove(elem) else: result.append(elem) return result l1 = [1,2,2,3] l2 = [1,2] print(remove_elems(l1, l2)) # -> [2, 3] 

Поделиться 26 декабря 2018 в 16:37

from collections import Counter list1 = [1, 2, 2, 2, 3] list2 = [1, 2, 2] counts = Counter(list2) result = [l for l in list1 if counts.get(l, 0) == 0 or counts.subtract((l,))] print(result) 

Output

Списковое включение эквивалентно:

result = [] for l in list1: if counts.get(l, 0) == 0 or counts.subtract((l,)): result.append(l) 

Сложная часть здесь — это оператор counts.get(l, 0) == 0 или counts.subtract((l,)) . counts.subtract((l,)) означает вычитание 1 из кол-ва l , а возвращаемое значение выражения — None , то, что None является булево-подобным значением (которое оценивается как False ), позволяет использовать его в одном выражении or . Таким образом, вышеуказанное или будет только True , когда counts.get(l, 0) == 0 .

Как вычесть из одного массива другой?

Author24 — интернет-сервис помощи студентам

вот код
Как сделать так, чтобы после нахождения максимума и минимума оставить список без этих двух элементов?

94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:

Как из одного массива пользовательских объектов вычесть другой
Собственно сабж. нужно это мне тут using assembly .\lib\LiteDB.dll using namespace.

Как вычесть из одного класса другой?
Вопрос такой, есть 2 класса в одном минуты секунды, во втором только секунды, не могу понять как.

Вычесть из одного массива байт другой массив байт
Здравствуйте! Подскажите что нужно сделать чтобы из одного массива байт вычесть другой массив байт!

Из одного списка, поэлементно вычесть другой
Списки могут быть разной длины. Помогите, сам не могу

Присвоить значения переменных, которые были получены из одного TextBox в другой и вычесть из него 1
Нужно присвоить значения переменных, которые были получены из тексбокс, в другой текст бокс и .

Пересечение списков, совпадающие элементы двух списков

В данной задаче речь идет о поиске элементов, которые присутствуют в обоих списках. При этом пересечение списков и поиск совпадающих (перекрывающихся) элементов двух списков будем считать несколько разными задачами.

Если даны два списка, в каждом из которых каждый элемент уникален, то задача решается просто, так как в результирующем списке не может быть повторяющихся значений. Например, даны списки:

[5, 4, 2, ‘r’, ‘ee’] и [4, ‘ww’, ‘ee’, 3]

Областью их пересечения будет список [4, ‘ee’] .

Если же исходные списки выглядят так:

[5, 4, 2, ‘r’, 4, ‘ee’, 4] и [4, ‘we’, ‘ee’, 3, 4] ,

то списком их совпадающих элементов будет [4, ‘ee’, 4] , в котором есть повторения значений, потому что в каждом из исходных списков определенное значение встречается не единожды.

Начнем с простого — поиска области пересечения. Cначала решим задачу «классическим» алгоритмом, не используя продвинутые возможностями языка Python: будем брать каждый элементы первого списка и последовательно сравнивать его со всеми значениями второго.

a = [5, [1, 2], 2, 'r', 4, 'ee'] b = [4, 'we', 'ee', 3, [1, 2]] c = [] for i in a: for j in b: if i == j: c.append(i) break print(c)

Результат выполнения программы:

[[1, 2], 4, 'ee']

Берется каждый элемент первого списка (внешний цикл for ) и последовательно сравнивается с каждым элементом второго списка (вложенный цикл for ). В случае совпадения значений элемент добавляется в третий список c . Команда break служит для выхода из внутреннего цикла, так как в случае совпадения дальнейший поиск при данном значении i бессмыслен.

Алгоритм можно упростить, заменив вложенный цикл на проверку вхождения элемента из списка a в список b с помощью оператора in :

a = [5, [1, 2], 2, 'r', 4, 'ee'] b = [4, 'we', 'ee', 3, [1, 2]] c = [] for i in a: if i in b: c.append(i) print(c)

Здесь выражение i in b при if по смыслу не такое как выражение i in a при for . В случае цикла оно означет извлечение очередного элемента из списка a для работы с ним в новой итерации цикла. Тогда как в случае if мы имеем дело с логическим выражением, в котором утверждается, что элемент i есть в списке b . Если это так, и логическое выражение возвращает истину, то выполняется вложенная в if инструкция, то есть элемент i добавляется в список c .

Принципиально другой способ решения задачи – это использование множеств. Подходит только для списков, которые не содержат вложенных списков и других изменяемых объектов, так как встроенная в Python функция set() в таких случаях выдает ошибку.

a = [5, 2, 'r', 4, 'ee'] b = [4, 1, 'we', 'ee', 'r'] c = list(set(a) & set(b)) print(c)
['ee', 4, 'r']

Выражение list(set(a) & set(b)) выполняется следующим образом.

  1. Сначала из списка a получают множество с помощью команды set(a) .
  2. Аналогично получают множество из b .
  3. С помощью операции пересечения множеств, которая обозначается знаком амперсанда & , получают третье множество, которое представляет собой область пересечения двух исходных множеств.
  4. Полученное таким образом третье множество преобразуют обратно в список с помощью встроенной в Python функции list() .

Множества не могут содержать одинаковых элементов. Поэтому, если в исходных списках были повторяющиеся значения, то уже на этапе преобразования этих списков во множества повторения удаляются, а результат пересечения множеств не будет отличаться от того, как если бы в исходных списках повторений не было.

Преобразование списков во множества с удалением повторяющихся значений

Однако если мы вернемся к решению задачи без использования множеств и добавим в первый список повтор значения, то получим некорректный результат:

Попадание в пересечение списков повторяющегося значения

В список пересечения попадают оба равных друг другу значения из первого списка. Это происходит потому, что когда цикл извлекает, в данном случае, вторую 4-ку из первого списка, выражение i in b также возвращает истину, как и при проверке первой 4-ки. Следовательно, выражение c.append(i) выполняется и для второй четверки.

Чтобы решить эту проблему, добавим дополнительное условие в заголовок инструкии if . Очередной значение i из списка a должно не только присутствовать в b , но его еще не должно быть в c . То есть это должно быть первое добавление такого значения в c :

a = [5, 2, 'r', 4, 'ee', 4] b = [4, 'we', 'ee', 3] c = [] for i in a: if i in b and i not in c: c.append(i) print(c)
[4, 'ee']

Теперь усложним задачу. Пусть если в обоих списках есть по несколько одинаковых значений, они должны попадать в список совпадающих элементов в том количестве, в котором встречаются в списке, где их меньше. Или если в исходных списках их равное количетво, то такое же количество должно быть в третьем. Например, если в первом списке у нас три 4-ки, а во втором две, то в третьем списке должно быть две 4-ки. Если в обоих исходных по две 4-ки, то в третьем также будет две.

Алгоритмом решения такой задачи может быть следующий:

  1. В цикле будем перебирать элементы первого списка.
  2. Если на текущей итерации цикла взятого из первого списка значения нет в третьем списке, то только в этом случае следует выполнять все нижеследующие действия. В ином случае такое значение уже обрабатывалось ранее, и его повторная обработка приведет к добавлению лишних элементов в результирующий список.
  3. С помощью спискового метода count() посчитаем количество таких значений в первом и втором списке. Выберем минимальное из них.
  4. Добавим в третий список количество элементов с текущим значением, равное ранее определенному минимуму.
a = [5, 2, 4, 'r', 4, 'ee', 1, 1, 4] b = [4, 1, 'we', 'ee', 'r', 4, 1, 1] c = [] for item in a: if item not in c: a_item = a.count(item) b_item = b.count(item) min_count = min(a_item, b_item) # c += [item] * min_count for i in range(min_count): c.append(item) print(c)
[4, 4, 'r', 'ee', 1, 1]

Если значение встречается в одном списке, но не в другом, то метод count() другого вернет 0. Соответственно, функция min() вернет 0, а цикл с условием i in range(0) не выполнится ни разу. Поэтому, если значение встречается в одном списке, но его нет в другом, оно не добавляется в третий.

При добавлении значений в третий список вместо цикла for можно использовать объединение списков с помощью операции + и операцию повторения элементов с помощью * . В коде выше данный способ показан в комментарии.

X Скрыть Наверх

Решение задач на Python

Удалить все значения из одного списка из другого списка? [Дубликат]

Что если у меня есть список [1,2,2,2,3,4] и [1,2,2,2,3,4] [2,3] , то результат должен быть [1,2,2,4] , есть ли Pythonic способ сделай это?

user 02 март 2014, в 05:20

@user Пользователь, это поможет вам пройти большую часть пути, но ваша проблема — это другая проблема! l = [1,2,2,3,4] sl = [2,3] [x для x в [l [n: n + 2] для n в диапазоне (0, len (l)) [:: 2 ]] если x! = sl]

jsh 23 март 2016, в 14:21

Если у вас нет повторяющихся значений, вы можете использовать разницу в настройках.

x = set(range(10)) y = x - set([2, 3, 7]) # y = set([0, 1, 4, 5, 6, 8, 9]) 

а затем при необходимости преобразуется обратно в список.

arunjitsingh 29 март 2012, в 20:47
Поделиться
Обратите внимание, что это перетасует результирующий список.
Neal Ehardt 04 дек. 2013, в 00:59

Порядок в списке может меняться, но детерминированным образом. Это не «перемешано» в случайном смысле.

dansalmo 25 дек. 2013, в 18:36
также, если ваш исходный список x имеет дубликаты, после операции set () сохраняется только один.
fast tooth 16 май 2014, в 19:34

@dansalmo сортируется по совокупности значений в зависимости от реализации набора и состояния различных ограничений памяти, присутствующих при создании сегментов. Я бы сказал, что это просто

njzk2 30 июль 2015, в 03:37
Показать ещё 2 комментария

a = range(1,10) itemsToRemove = set([2, 3, 7]) b = filter(lambda x: x not in itemsToRemove, a) 
b = [x for x in a if x not in itemsToRemove] 

Не создавайте набор внутри lambda или внутри понимания. Если вы это сделаете, он будет воссоздан на каждой итерации, полностью разбив точку использования набора.

Yaroslav 25 март 2010, в 12:55
Поделиться
За исключением того, что он создает N наборов, N из которых len (a).
FogleBird 25 март 2010, в 12:16
Он создает только один набор при создании лямбда-функции
Xavier Combelle 25 март 2010, в 12:30
Хороший вопрос, FogleBird. Нужно создать его вне лямбды или списка понимания.
Yaroslav 25 март 2010, в 12:33

Ксавье, FogleBird прав. Вы можете доказать это, создав функцию-обертку ‘set’, которая считает его вызовы.

Yaroslav 25 март 2010, в 12:34

Использование filter с анонимной функцией глупо. Понимание списка имеет гораздо больше смысла в этом случае использования.

Mike Graham 25 март 2010, в 15:52
Показать ещё 3 комментария

Я искал быстрый способ сделать этот вопрос, поэтому я сделал несколько экспериментов с предложенными способами. И я был удивлен результатами, поэтому хочу поделиться им с вами.

Эксперименты проводились с использованием инструмента pythonbenchmark и с

a = range(1,50000) # Source list b = range(1,15000) # Items to remove 
 def comprehension(a, b): return [x for x in a if x not in b] 

5 попыток, среднее время 12,8 с

def filter_function(a, b): return filter(lambda x: x not in b, a) 

5 попыток, среднее время 12,6 секунд

def modification(a,b): for x in b: try: a.remove(x) except ValueError: pass return a 

5 попыток, среднее время 0,27 с

def set_approach(a,b): return list(set(a)-set(b)) 

5 попыток, среднее время 0.0057 сек

Также я сделал еще одно измерение с большим размером входов для двух последних функций

a = range(1,500000) b = range(1,100000) 

Для модификации (метод удаления) — среднее время составляет 252 секунды Для заданного подхода — среднее время 0,75 секунд

Итак, вы можете видеть, что подход с наборами значительно быстрее, чем другие. Да, он не хранит похожие предметы, но если вам это не нужно — это для вас. И нет никакой разницы между пониманием списка и использованием функции фильтра. Использование ‘remove’ в ~ 50 раз быстрее, но оно изменяет список источников. И лучший выбор — использование наборов — это более чем в 1000 раз быстрее, чем понимание списка!

The Godfather 20 май 2015, в 16:26
Поделиться

очень интересно. Я бы не использовал set, интуитивно понятное преобразование должно добавить накладных расходов. видимо моя интуиция была не права. спасибо за понимание

lhk 07 дек. 2016, в 09:58

Очень хороший ответ, спасибо! Наборы намного быстрее, потому что время нахождения элемента линейно, поскольку набор Python реализован в виде хеш-таблицы. Следовательно, для удаления элемента из набора не нужно тратить время на поиск элемента, тогда как в списке элемент должен быть найден первым.

Guillem Cucurull 15 авг. 2018, в 21:24

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

newl = [x for x in l if x not in [2,3,7]] 
newl = filter(lambda x: x not in [2,3,7], l) 

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

l = range(1,10) for o in set([2,3,7,11]): try: l.remove(o) except ValueError: pass print l 

Выход: [1, 4, 5, 6, 8, 9]

Я проверяю исключение ValueError, поэтому он работает, даже если элементы не находятся в оригинальном списке.

Также, если вам не требуется исправление на месте с помощью S.Mark , это проще.

Anurag Uniyal 25 март 2010, в 13:30
Поделиться

если вам действительно требуется модификация на месте, предыдущие ответы можно изменить на: a[:] = [x for x in a if x not in [2,3,7]] . Это будет быстрее, чем ваш код.

Seth Johnson 25 март 2010, в 13:35

да, можно использовать [:], но не очевидно, что это будет быстрее, поскольку для длинных списков с несколькими значениями удалить мой код будет намного быстрее, например, попытаться удалить список из списка = [1] 🙂

Anurag Uniyal 25 март 2010, в 14:01
@Anurag: Вы, кажется, правы; временные тесты заставляют это выглядеть как удаление на месте быстрее.
Seth Johnson 25 март 2010, в 14:49

То, что вам нужно сделать, если вы хотите использовать l.remove remove это снова и снова вызывать цикл l.remove пока не получите ValueError и в этот момент этот цикл не l.remove . Это будет учитывать случай, когда в списке есть несколько вхождений значения. (Лучшее решение по-прежнему остается первым.)

Mike Graham 25 март 2010, в 15:57
@Seth Сет Джонсон, преждевременная оптимизация много?
Mike Graham 25 март 2010, в 15:57

@Mike: нет, но я надеялся, что более чистая (короткая однострочная) версия будет лучше. Я не использую Python, когда хочу оптимизированный код. Я использую C ++ с SWIG. 🙂

Seth Johnson 25 март 2010, в 18:00

@Seth Сэт Джонсон, «Лучше» не значит «быстрее», особенно если не доказано, что фрагмент кода замедляет работу приложения. Критерии, такие как корректность (к которой не относится опция remove ), удобочитаемость, тестируемость и ремонтопригодность, почти всегда важнее.

Mike Graham 25 март 2010, в 18:28
Идея remove отлично подходит для списков, содержащих объекты dict .
rob 09 март 2016, в 19:22
Показать ещё 6 комментариев

Самый простой способ —

>>> a = range(1, 10) >>> for x in [2, 3, 7]: . a.remove(x) . >>> a [1, 4, 5, 6, 8, 9] 

Одна из возможных проблем заключается в том, что каждый раз, когда вы вызываете remove(), все элементы перетасовываются по списку, чтобы заполнить отверстие. Поэтому, если a растет очень сильно, это будет довольно медленным.

Таким образом создается новый список. Преимущество состоит в том, что мы избегаем всех перетасовки первого подхода

>>> removeset = set([2, 3, 7]) >>> a = [x for x in a if x not in removeset] 

Если вы хотите изменить a на месте, требуется только одно небольшое изменение

>>> removeset = set([2, 3, 7]) >>> a[:] = [x for x in a if x not in removeset] 

John La Rooy 25 март 2010, в 13:01
Поделиться

@gnibbler, Ваше заявление «Так что, если растет очень велико , то это в конечном итоге довольно медленно.» a немного вводит в заблуждение. Если только длина a не ограничена, все предоставленные вами фрагменты O (n). Настоящая проблема с remove заключается в том, что он удаляет только первое вхождение своих аргументов, а не все вхождения. Кроме того, в целом лучше писать чистый идиоматический код, чтобы создать новый список, а не менять старый.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *