Это делает то, что вы хотите, и будет работать почти во всех случаях:
>>> all(x in ['b', 'a', 'foo', 'bar'] for x in ['a', 'b'])
True
Выражение 'a','b' in ['b', 'a', 'foo', 'bar']
работает не так, как ожидалось, потому что Python интерпретирует его как кортеж:
>>> 'a', 'b'
('a', 'b')
>>> 'a', 5 + 2
('a', 7)
>>> 'a', 'x' in 'xerxes'
('a', True)
Другие варианты
Есть и другие способы выполнить этот тест, но они не будут работать для такого количества различных типов входных данных. Как указывает Кэби , вы можете решить эту проблему, используя наборы ...
>>> set(['a', 'b']).issubset(set(['a', 'b', 'foo', 'bar']))
True
>>> {'a', 'b'} <= {'a', 'b', 'foo', 'bar'}
True
...иногда:
>>> {'a', ['b']} <= {'a', ['b'], 'foo', 'bar'}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
Наборы могут быть созданы только с хешируемыми элементами. Но выражение генератора all(x in container for x in items)
может обрабатывать практически любой тип контейнера. Единственное требование - это container
повторение (т. Е. Не генератор). items
может быть любым итеративным.
>>> container = [['b'], 'a', 'foo', 'bar']
>>> items = (i for i in ('a', ['b']))
>>> all(x in [['b'], 'a', 'foo', 'bar'] for x in items)
True
Тесты на скорость
Во многих случаях тест подмножества будет быстрее all
, но разница не шокирует - за исключением случаев, когда вопрос не имеет значения, потому что наборы не являются вариантом. Преобразование списков в наборы только для целей подобного теста не всегда стоит усилий. А преобразование генераторов в наборы иногда может быть невероятно расточительным, замедляя выполнение программ на много порядков.
Вот несколько тестов для иллюстрации. Самая большая разница возникает , когда оба container
и items
относительно невелики. В этом случае подход с использованием подмножеств примерно на порядок быстрее:
>>> smallset = set(range(10))
>>> smallsubset = set(range(5))
>>> %timeit smallset >= smallsubset
110 ns ± 0.702 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
>>> %timeit all(x in smallset for x in smallsubset)
951 ns ± 11.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Похоже, это большая разница. Но пока container
это набор, его all
можно использовать в гораздо больших масштабах:
>>> bigset = set(range(100000))
>>> bigsubset = set(range(50000))
>>> %timeit bigset >= bigsubset
1.14 ms ± 13.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
>>> %timeit all(x in bigset for x in bigsubset)
5.96 ms ± 37 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Тестирование подмножества все еще быстрее, но только примерно в 5 раз в этом масштабе. Повышение скорости связано с быстрой c
реализацией Python set
, но основной алгоритм одинаков в обоих случаях.
Если items
они уже сохранены в списке по другим причинам, вам придется преобразовать их в набор, прежде чем использовать подход тестирования подмножества. Затем ускорение падает примерно до 2,5 раз:
>>> %timeit bigset >= set(bigsubseq)
2.1 ms ± 49.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
А если ваша container
последовательность, и ее нужно сначала преобразовать, то ускорение еще меньше:
>>> %timeit set(bigseq) >= set(bigsubseq)
4.36 ms ± 31.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Единственный раз, когда мы получаем катастрофически медленные результаты, - это когда мы уходим container
в виде последовательности:
>>> %timeit all(x in bigseq for x in bigsubseq)
184 ms ± 994 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
И, конечно, мы сделаем это только в случае необходимости. Если все элементы bigseq
хешируются, мы сделаем это вместо этого:
>>> %timeit bigset = set(bigseq); all(x in bigset for x in bigsubseq)
7.24 ms ± 78 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Это всего в 1,66 раза быстрее, чем у альтернативы ( set(bigseq) >= set(bigsubseq)
рассчитано выше на 4,36).
Таким образом, тестирование подмножества, как правило, происходит быстрее, но не намного. С другой стороны, давайте посмотрим, когда all
быстрее. Что, если items
длина составляет десять миллионов значений, и, скорее всего, у них есть значения, которых нет container
?
>>> %timeit hugeiter = (x * 10 for bss in [bigsubseq] * 2000 for x in bss); set(bigset) >= set(hugeiter)
13.1 s ± 167 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit hugeiter = (x * 10 for bss in [bigsubseq] * 2000 for x in bss); all(x in bigset for x in hugeiter)
2.33 ms ± 65.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Преобразование генератора в комплект в этом случае оказывается невероятно расточительным. set
Конструктор должен потреблять весь генератор. Но короткое замыкание all
гарантирует, что потребляется лишь небольшая часть генератора, поэтому он быстрее, чем тест подмножества, на четыре порядка .
По общему признанию, это крайний пример. Но, как видно, нельзя предполагать, что тот или иной подход будет быстрее во всех случаях.
The Upshot
В большинстве случаев преобразование container
в набор того стоит, по крайней мере, если все его элементы хешируемы. Это потому, что in
для наборов - O (1), а in
для последовательностей - O (n).
С другой стороны, использование тестирования подмножества, вероятно, того стоит только иногда. Обязательно сделайте это, если ваши тестовые задания уже хранятся в наборе. В противном случае all
он работает немного медленнее и не требует дополнительного хранилища. Его также можно использовать с большими генераторами предметов и в этом случае иногда обеспечивает значительное ускорение.
set(['a', 'b']) <= set(['b','a','foo','bar'])
это еще один способ записать одно и то же, и он выглядит «математичнее».{'a', 'b'} <= {'b','a','foo','bar'}
Я почти уверен
in
, что у него более высокий приоритет, чем,
ваш оператор интерпретируется как'a', ('b' in ['b' ...])
, который затем оценивается как'a', True
поскольку'b'
находится в массиве.См. Предыдущий ответ, чтобы узнать, как делать то, что вы хотите.
источник
Если вы хотите проверить все свои входные совпадения ,
если вы хотите проверить хотя бы одно совпадение ,
источник
Синтаксический анализатор Python оценил этот оператор как кортеж, где было первое значение
'a'
, а второе значение - это выражение'b' in ['b', 'a', 'foo', 'bar']
(которое оценивается какTrue
).Вы можете написать простую функцию, делающую то, что вы хотите:
И назовите это так:
источник
Причина, по которой я считаю, что это лучше, чем выбранный ответ, заключается в том, что вам действительно не нужно вызывать функцию all (). Пустой список оценивается как False в операторах IF, непустой список оценивается как True.
Пример:
источник
Я бы сказал, что мы можем даже опустить эти квадратные скобки.
источник
Оба представленных здесь ответа не будут обрабатывать повторяющиеся элементы. Например, если вы проверяете, является ли [1,2,2] подсписком [1,2,3,4], оба вернут True. Возможно, вы хотите это сделать, но я просто хотел уточнить. Если вы хотите вернуть false для [1,2,2] в [1,2,3,4], вам нужно будет отсортировать оба списка и проверить каждый элемент с движущимся индексом в каждом списке. Просто немного более сложный цикл for.
источник
как можно быть питонистом без лямбд! .. не воспринимать всерьез .. но этот способ тоже работает:
оставьте конечную часть, если хотите проверить, есть ли какие-либо значения в массиве:
источник
filter
есть генератор. Вам нужно будет обернуть его,list
если вы действительно хотите получить результат, который вы могли бы протестировать с помощью==
или в логическом контексте (чтобы увидеть, пуст ли он). Предпочтительно использование списка или выражения генератора вany
илиall
.Вот как я это сделал:
источник