Я хочу сделать что-то похожее на это:
>>> x = [1,2,3,4,5,6,7,8,9,0]
>>> x
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
>>> y = [1,3,5,7,9]
>>> y
[1, 3, 5, 7, 9]
>>> y - x # (should return [2,4,6,8,0])
Но это не поддерживается списками Python. Каков наилучший способ сделать это?
Ответы:
Используйте понимание списка:
Если вы хотите использовать
-
синтаксис инфикса, вы можете просто сделать:затем вы можете использовать его как:
Но если вам совершенно не нужны свойства списка (например, порядок), просто используйте наборы, как рекомендуют другие ответы.
источник
list
для имен переменных, поскольку это скрываетlist
конструктор. Если вы используете «список», пожалуйста, поставьте перед ним подчеркивание. Кроме того, отбросив*
, вы взломали мой код ...[1,1,2,2] - [1,2]
вы получите пустой список.[1,1,2,2] - [2]
дает[1,1]
Так что это на самом деле не вычитание списка, это больше похоже на «Список из списка X без элементов из набора Y » .y
в (что аналогично стоимости оригинальной работы). Вам нужно было бы либо выполнить за пределами listcomp, затем протестировать , либо в качестве вопиющего хакерства , которое использует вложенные списки списков для кэширования как однострочного. Немного менее уродливое однострочное решение, которое работает адекватно, будет состоять в использовании, потому что аргумент to создается только один раз.set
yset = set(y)
if item not in yset
[item for yset in [set(y)] for item in x if item not in yset]
yset
list(itertools.filterfalse(set(y).__contains__, x))
filterfalse
Использовать установленную разницу
Или вы можете просто установить x и y, чтобы вам не приходилось делать какие-либо преобразования.
источник
TypeError: unhashable type: 'dict'
Это операция «установить вычитание». Используйте для этого заданную структуру данных.
В Python 2.7:
Вывод:
источник
Если дубликаты и заказы являются проблемой:
[i for i in a if not i in b or b.remove(i)]
источник
O(m * n)
выполнения (и я съеживаюсь всякий раз, когда listcomp включает побочные эффекты); вы можете улучшить его, используяcollections.Counter
для полученияO(m + n)
времени выполнения.Для многих случаев использования вы хотите получить ответ:
Это гибрид между ответом aaronasterling в и ответ quantumSoup в .
Версия aaronasterling выполняет
len(y)
сравнение элементов для каждого элементаx
, поэтому требуется квадратичное время. В версии QuantumSoup используются наборы, поэтому для каждого элемента выполняется поиск по одному набору с постоянным временем,x
но, поскольку он преобразует обаx
иy
в наборы, он теряет порядок ваших элементов.Преобразуя только
y
в набор и повторяяx
по порядку, вы получаете лучшее из обоих миров - линейного времени и сохранения порядка. *Однако в версии QuantumSoup все еще есть проблема: она требует, чтобы ваши элементы были хэшируемыми. Это в значительной степени встроено в природу наборов. ** Если вы пытаетесь, например, вычесть список диктов из другого списка, но список для вычитания велик, что вы делаете?
Если вы можете украсить ваши значения так, чтобы они были хэшируемыми, это решит проблему. Например, с плоским словарем, значения которого сами по себе могут быть хэшируемыми:
Если ваши типы немного сложнее (например, вы часто имеете дело с JSON-совместимыми значениями, которые являются хэшируемыми, или списками или указаниями, значения которых имеют рекурсивный тип), вы все равно можете использовать это решение. Но некоторые типы просто не могут быть преобразованы во что угодно
Если ваши элементы не являются и не могут быть сделаны хэшируемыми, но они сопоставимы, вы можете, по крайней мере, получить логарифмическое время (
O(N*log M)
что намного лучше, чемO(N*M)
время решения списка, но не так хорошо, какO(N+M)
время заданного раствора) путем сортировки и с помощьюbisect
:Если ваши элементы не являются ни хэшируемыми, ни сопоставимыми, то вы застряли с квадратичным решением.
* Обратите внимание, что вы также можете сделать это, используя пару
OrderedSet
объектов, для которых вы можете найти рецепты и сторонние модули. Но я думаю, что это проще.** Причина, по которой поиск выполняется с постоянным временем, заключается в том, что все, что ему нужно сделать, - это хэшировать значение и посмотреть, есть ли запись для этого хэша. Если он не может хэшировать значение, это не сработает.
источник
Поиск значений в наборах происходит быстрее, чем поиск в списках:
Я считаю, что это будет немного лучше, чем:
Оба сохраняют порядок списков.
источник
set(y)
и не преобразовыватьсяy
в новый набор в каждом цикле? В противном случае, вы бы ответ нужно abarnert в:ys = set(y); [i for i in x if i not in ys]
.if i not in set(y)
занимает на 25% больше времениif i not in y
( чемy
список). Предварительное преобразование набора занимает на 55% меньше времени. Протестировано с довольно короткимиx
иy
, но различия должны стать более выраженными с длиной, во всяком случае.y
для каждого элементаx
; если сравнение на равенство не является действительно дорогим по сравнению с вычислением хеша, это всегда будет проигнорированоitem not in y
.Если списки допускают дублирование элементов, вы можете использовать Counter из коллекций:
Если вам нужно сохранить порядок элементов из x:
источник
Counter.subtract
не удаляет элементы с нулевым значением (-
и не-=
делаетsubtract
), поэтому вы никогда не прекратите удалять элементы. Вы хотите заменитьnot v in c
наnot c[v]
(который возвращает ноль для несуществующих элементов, так что вы можете безопасно проверить возврат на «нулевое значение» черезnot
).Я думаю, что самый простой способ добиться этого - использовать set ().
источник
Другие решения имеют одну из нескольких проблем:
x = [1, 2, 2, 2]
иy = [2, 2]
преобразуютy
в aset
, и либо удаляют все совпадающие элементы (оставляя[1]
только), либо удаляют один из каждого уникального элемента (оставляя[1, 2, 2]
), когда правильное поведение будет удалять2
дважды, оставляя[1, 2]
илиO(m * n)
работают, где оптимальное решение можетO(m + n)
работатьАлен был на правильном пути,
Counter
чтобы решить # 2 и # 3, но это решение потеряет порядок. Решение, которое сохраняет порядок (удаление первыхn
копий каждого значения дляn
повторений вlist
значениях для удаления):Попробуйте онлайн!
Чтобы удалить последние копии каждого элемента, просто измените
for
цикл наfor val in reversed(x):
и добавьтеout.reverse()
сразу после выхода изfor
цикла.Построение
Counter
выражаетсяO(n)
в единицахy
длины, итерацииx
-O(n)
в единицахx
длины, аCounter
тестирование членства и мутацииO(1)
покаlist.append
амортизируютсяO(1)
(данныеappend
могут бытьO(n)
, но для многихappend
с, общие средние значения big-O,O(1)
так как все меньше и меньше из них требуют перераспределения), поэтому общая работа сделанаO(m + n)
.Вы также можете проверить, чтобы определить, были ли какие-либо элементы
y
, которые не были удаленыx
при тестировании:источник
int
с на массив фиксированной длиной) или должен сделать больше , чемO(m + n)
работы (например , следующим лучшим масштабно -O будет состоять в том, чтобы отсортироватьlist
пары уникальных значений / счетчиков, превративO(1)
dict
поиски вO(log n)
бинарные поиски; вам понадобятся уникальные значения с их счетами, а не просто отсортированные неуникальные значения, потому что в противном случае вы бы заплатилиO(n)
расходы на удаление элементы из отсортированногоlist
).Попробуй это.
источник
Ответ предоставляется @aaronasterling выглядит хорошо, однако, он не совместим с интерфейсом по умолчанию списка:
x = MyList(1, 2, 3, 4)
противx = MyList([1, 2, 3, 4])
. Таким образом, приведенный ниже код может использоваться как более дружественный к списку Python:Пример:
источник
Я думаю это быстрее
источник
Этот пример вычитает два списка:
источник