Як перевірити, чи є один із наведених нижче пунктів у списку?


220

Я намагаюся знайти короткий шлях, щоб дізнатися, чи є якийсь із наведених нижче пунктів у списку, але моя перша спроба не спрацює. Окрім написання функції для цього, є будь-який короткий спосіб перевірити, чи є один із кількох елементів у списку.

>>> a = [2,3,4]
>>> print (1 or 2) in a
False
>>> print (2 or 1) in a
True

Дивна річ, я перевірив, як поводиться «і». a = [1, 2] b = [3, 5, 2, 6, 8, 9] c = [3, 5, 6, 8, 1, 9] print( (1 and 2) in b ,(2 and 1) in b ,(1 and 2) in c ,(2 and 1) in c, sep='\n')True True False False True
Piotr Kamoda

Відповіді:


266
>>> L1 = [2,3,4]
>>> L2 = [1,2]
>>> [i for i in L1 if i in L2]
[2]


>>> S1 = set(L1)
>>> S2 = set(L2)
>>> S1.intersection(S2)
set([2])

І порожні списки, і порожні набори є помилковими, тому ви можете використовувати значення безпосередньо як значення істини.


6
Ідея перетину дала мені цю ідею. повернення len (set (a). перехрестя (set (b)))
Deon

14
FWIW - я зробив порівняння швидкості, і найпершим рішенням, запропонованим тут, було на сьогоднішній день.
jackiekazil

2
@ відповідь user89788 з використанням генератора знову набагато швидше, тому що anyможе повернутися рано, як тільки знайде Trueзначення - не потрібно спочатку будувати весь список
Anentropic

Рішення другого / набору не працюватиме, якщо у списку є дублікати (оскільки набори містять лише один елемент). Якщо `L1 = [1,1,2,3] 'і' L2 = [1,2,3] ', всі елементи будуть видно, що перетинаються.
дорондадон

Я знаю, що це майже 10 років, але перше рішення, здається, не працює для мене. Я замінив числа в L2 на рядки, і я отримую таку помилку: TypeError: 'in <string>' вимагає рядок як лівий операнд, а не список
roastbeeef

227

Ах, Тобіас, ти мене до цього побив. Я думав про цю незначну варіацію вашого рішення:

>>> a = [1,2,3,4]
>>> b = [2,7]
>>> print(any(x in a for x in b))
True

5
Я усвідомлюю, що це дуже стара відповідь, але якщо один список дуже довгий, а другий короткий, чи є порядок, який дасть швидші результати? (тобто, x in long for x in shortпроти x in short for x in long)
Лука Сапан

11
@LukeSapan: Ви маєте рацію. Таке замовлення можна отримати за допомогою "надрукувати будь-яке (x in max (a, b, key = len) для x in min (a, b, key = len))". При цьому використовується x in long, а x коротше.
Ядерник

2
Це найкраща відповідь, тому що він використовує генератор і повернеться, як тільки буде знайдено відповідність (як інші сказали, просто не на цю відповідь!).
доктролі

4
@Nuclearman, бережися: Якщо ці два списки aі bмають однакову довжину, максимальний і мінімальний поверне найлівіший список, що робить any()виклик працювати над тим же списком з обох сторін. Якщо ви абсолютно вимагають перевірки довжини в зворотному порядку списків в другому виклику: any(x in max(a, b, key=len) for x in (b, a, key=len)).
Ной Богарт

3
@NoahBogart Ви маєте рацію, і це рішення виглядає так само добре, як і будь-яке. Я також припускаю, що ви мали на увазі: any(x in max(a, b, key=len) for x in min(b, a, key=len))(пропустив хв).
Ядерник

29

Можливо, трохи лінивіше:

a = [1,2,3,4]
b = [2,7]

print any((True for x in a if x in b))

1
Це майже те саме, що і те, що я розмістив.
Бастієн Леонард

5
@ BastienLéonard ... за винятком того, що це набагато швидше, оскільки він використовує генератор і, таким чином, anyможе повернутися рано, тоді як ваша версія повинна скласти весь список з розуміння, перш ніж anyможна використовувати його. @ user89788 відповідь дещо краща, оскільки подвійні дужки є непотрібними
Anentropic

17

Подумайте, що насправді говорить код!

>>> (1 or 2)
1
>>> (2 or 1)
2

Це, мабуть, повинно це пояснити. :) Python, мабуть, реалізує "ледачий або", що не повинно бути несподіванкою. Він виконує це приблизно так:

def or(x, y):
    if x: return x
    if y: return y
    return False

У першому прикладі x == 1і y == 2. У другому прикладі - навпаки. Ось чому він повертає різні значення залежно від їх порядку.


16
a = {2,3,4}
if {1,2} & a:
    pass

Версія коду для гольфу. Подумайте про використання набору, якщо це має сенс зробити. Я вважаю це більш зрозумілим, ніж розуміння списку.


12

1 рядок без розуміння списку.

>>> any(map(lambda each: each in [2,3,4], [1,2]))
True
>>> any(map(lambda each: each in [2,3,4], [1,5]))
False
>>> any(map(lambda each: each in [2,3,4], [2,4]))
True


6

У python 3 ми можемо почати використовувати розпаковувану зірочку. Дано два списки:

bool(len({*a} & {*b}))

Редагувати: включити пропозицію алканена


1
@Anthony, він створює набір, що містить елементи в a, а інший набір, що містить елементи в b, тоді він знаходить перетин (спільні елементи) між цими множинами, а будь-який () повертає істиною, якщо є такі елементи, які є правдоподібними. Розв’язання не працюватиме, якщо єдині спільні (-і) елементи (-и) є хибними (наприклад, число 0). Можливо, буде краще використовувати len (), ніж будь-який ()
alkanen

1
@alkanen Хороший дзвінок
Даніель Браун

чому б не використовувати задану функцію?
Alex78191

5

Коли ви думаєте "перевірити, чи є a в b", подумайте хеши (у цьому випадку встановлюється). Найшвидший спосіб - хеш-лист списку, який ви хочете перевірити, а потім перевірити кожен елемент там.

Ось чому відповідь Джо Коберга швидка: перевірка встановленого перехрестя дуже швидка.

Якщо у вас немає багато даних, виготовлення наборів може бути марною тратою часу. Отже, ви можете скласти набір списку і просто перевірити кожен елемент:

tocheck = [1,2] # items to check
a = [2,3,4] # the list

a = set(a) # convert to set (O(len(a)))
print [i for i in tocheck if i in a] # check items (O(len(tocheck)))

Коли кількість предметів, які ви хочете перевірити, невелика, різниця може бути незначною. Але порівняйте велику кількість з великим списком ...

тести:

from timeit import timeit

methods = ['''tocheck = [1,2] # items to check
a = [2,3,4] # the list
a = set(a) # convert to set (O(n))
[i for i in tocheck if i in a] # check items (O(m))''',

'''L1 = [2,3,4]
L2 = [1,2]
[i for i in L1 if i in L2]''',

'''S1 = set([2,3,4])
S2 = set([1,2])
S1.intersection(S2)''',

'''a = [1,2]
b = [2,3,4]
any(x in a for x in b)''']

for method in methods:
    print timeit(method, number=10000)

print

methods = ['''tocheck = range(200,300) # items to check
a = range(2, 10000) # the list
a = set(a) # convert to set (O(n))
[i for i in tocheck if i in a] # check items (O(m))''',

'''L1 = range(2, 10000)
L2 = range(200,300)
[i for i in L1 if i in L2]''',

'''S1 = set(range(2, 10000))
S2 = set(range(200,300))
S1.intersection(S2)''',

'''a = range(200,300)
b = range(2, 10000)
any(x in a for x in b)''']

for method in methods:
    print timeit(method, number=1000)

швидкості:

M1: 0.0170331001282 # make one set
M2: 0.0164539813995 # list comprehension
M3: 0.0286040306091 # set intersection
M4: 0.0305438041687 # any

M1: 0.49850320816 # make one set
M2: 25.2735087872 # list comprehension
M3: 0.466138124466 # set intersection
M4: 0.668627977371 # any

Послідовно швидкий метод полягає в тому, щоб зробити один набір (зі списку), але перетин працює на великих наборах даних найкращим чином!


3

У деяких випадках (наприклад, унікальні елементи списку) можуть використовуватися задані операції.

>>> a=[2,3,4]
>>> set(a) - set([2,3]) != set(a)
True
>>> 

Або, використовуючи set.isdisjoint () ,

>>> not set(a).isdisjoint(set([2,3]))
True
>>> not set(a).isdisjoint(set([5,6]))
False
>>> 

2

Це зробить це в один рядок.

>>> a=[2,3,4]
>>> b=[1,2]
>>> bool(sum(map(lambda x: x in b, a)))
True

Я не отримую істинного тут >>> надрукувати a [2, 3, 4] >>> надрукувати b [2, 7] >>> зменшити (лямбда x, y: x in b, a) False
Deon

Так. Ти маєш рацію. redu () не зовсім обробляв булеві значення так, як я думав, що це буде. Переглянута версія, яку я писав вище, працює і для цього випадку.
Кріс Upchurch

2

Я зібрав декілька рішень, згаданих в інших відповідях та коментарях, потім пройшов тест на швидкість. not set(a).isdisjoint(b)виявився найшвидшим, він також не сильно сповільнився, коли був результат False.

Кожен з трьох циклів тестує невеликий зразок можливих конфігурацій aта b. Часи в мікросекундах.

Any with generator and max
        2.093 1.997 7.879
Any with generator
        0.907 0.692 2.337
Any with list
        1.294 1.452 2.137
True in list
        1.219 1.348 2.148
Set with &
        1.364 1.749 1.412
Set intersection explcit set(b)
        1.424 1.787 1.517
Set intersection implicit set(b)
        0.964 1.298 0.976
Set isdisjoint explicit set(b)
        1.062 1.094 1.241
Set isdisjoint implicit set(b)
        0.622 0.621 0.753

import timeit

def printtimes(t):
    print '{:.3f}'.format(t/10.0),

setup1 = 'a = range(10); b = range(9,15)'
setup2 = 'a = range(10); b = range(10)'
setup3 = 'a = range(10); b = range(10,20)'

print 'Any with generator and max\n\t',
printtimes(timeit.Timer('any(x in max(a,b,key=len) for x in min(b,a,key=len))',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('any(x in max(a,b,key=len) for x in min(b,a,key=len))',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('any(x in max(a,b,key=len) for x in min(b,a,key=len))',setup=setup3).timeit(10000000))
print

print 'Any with generator\n\t',
printtimes(timeit.Timer('any(i in a for i in b)',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('any(i in a for i in b)',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('any(i in a for i in b)',setup=setup3).timeit(10000000))
print

print 'Any with list\n\t',
printtimes(timeit.Timer('any([i in a for i in b])',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('any([i in a for i in b])',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('any([i in a for i in b])',setup=setup3).timeit(10000000))
print

print 'True in list\n\t',
printtimes(timeit.Timer('True in [i in a for i in b]',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('True in [i in a for i in b]',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('True in [i in a for i in b]',setup=setup3).timeit(10000000))
print

print 'Set with &\n\t',
printtimes(timeit.Timer('bool(set(a) & set(b))',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('bool(set(a) & set(b))',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('bool(set(a) & set(b))',setup=setup3).timeit(10000000))
print

print 'Set intersection explcit set(b)\n\t',
printtimes(timeit.Timer('bool(set(a).intersection(set(b)))',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('bool(set(a).intersection(set(b)))',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('bool(set(a).intersection(set(b)))',setup=setup3).timeit(10000000))
print

print 'Set intersection implicit set(b)\n\t',
printtimes(timeit.Timer('bool(set(a).intersection(b))',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('bool(set(a).intersection(b))',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('bool(set(a).intersection(b))',setup=setup3).timeit(10000000))
print

print 'Set isdisjoint explicit set(b)\n\t',
printtimes(timeit.Timer('not set(a).isdisjoint(set(b))',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('not set(a).isdisjoint(set(b))',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('not set(a).isdisjoint(set(b))',setup=setup3).timeit(10000000))
print

print 'Set isdisjoint implicit set(b)\n\t',
printtimes(timeit.Timer('not set(a).isdisjoint(b)',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('not set(a).isdisjoint(b)',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('not set(a).isdisjoint(b)',setup=setup3).timeit(10000000))
print

0

Я мушу сказати, що моя ситуація може бути не такою, яку ви шукаєте, але це може стати альтернативою вашому мисленню.

Я спробував як set (), так і будь-який () метод, але все ще є проблеми зі швидкістю. Тому я згадав, як Реймонд Хеттінгер сказав, що все в python - це словник, і використовуйте dict, коли можете. Так що я спробував.

Я використовував за замовчуванням int для позначення негативних результатів і використовував елемент у першому списку як ключ для другого списку (перетворений на дефолт). Оскільки у вас є миттєвий пошук з dict, ви відразу знаєте, чи існує цей елемент у вирок за замовчуванням. Я знаю, що вам не завжди вдається змінити структуру даних для вашого другого списку, але якщо ви зможете з самого початку, це набагато швидше. Можливо, вам доведеться перетворити list2 (більший список) у вирок за замовчуванням, де ключовим є потенційне значення, яке ви хочете перевірити з невеликого списку, а значення - 1 (хіт) або 0 (без звернення, за замовчуванням).

from collections import defaultdict
already_indexed = defaultdict(int)

def check_exist(small_list, default_list):
    for item in small_list:
        if default_list[item] == 1:
            return True
    return False

if check_exist(small_list, already_indexed):
    continue
else:
    for x in small_list:
        already_indexed[x] = 1

-4

Простий.

_new_list = []
for item in a:
    if item in b:
        _new_list.append(item)
    else:
        pass

1
Це не дає відповіді на запитання. ОП хоче знати, чи є в списку якесь значення зі a списку b.
That1Guy
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.