Проверка наличия элемента списка в списке списков и возврат подсписка

#python #python-3.x #list #any

#python #python-3.x #Список #Любой

Вопрос:

У меня есть два списка

 list1 = ['B', 'C', 'D']
list2 = [['1', 'A'], ['2', 'B'], ['3', 'D'], ['5', 'C']]
  

и хотите вернуть те подсписки list2, которые содержат элементы list1.
До сих пор я пытался использовать любой:

 result = []

for l2 in list2:
    if any (item in l2 for item in list1):
        result.append(l2)
  

и наивный подход

 for l2 in list2:
    for l1 in l1:
        if l1 in l2:
            result.append(l2)
  

Но мне удалось только повторить пустой список.
Результат должен быть

 result = [['2', 'B'], ['5', 'C']]
  

Не уверен, где я ошибаюсь. Может быть, есть способ использовать понимание списка или смешивать понимание списка и «любую» функцию?

Комментарии:

1. Где это ['3', 'D'] ?

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

3. То же самое относится и ко второму фрагменту кода — за исключением опечатки: for l1 in list1:

Ответ №1:

То, что у вас есть, выглядит правильно и работает для меня локально тоже:

 for l2 in list2:
    if any (item in l2 for item in list1):
        result.append(l2)
  

Он возвращает [['2', 'B'], ['3', 'D'], ['5', 'C']] ожидаемый результат, верно?

Также обратите внимание, что вы можете ускорить свою реализацию, изменив list1 на set list1 = set(['B', 'C', 'D']) и изменив условие if на if any (item in list1 for item in l2): .
Это потому item in list1 , что намного быстрее, если list1 a set , чем a list . Это потому set , что использует hashmap под капотом для быстрого доступа к элементам.

Ответ №2:

Попробуйте это:

 result=[i for i in list2 if any([k in i for k in list1])]
print(result)

[['2', 'B'], ['3', 'D'], ['5', 'C']]
  

Ответ №3:

Если элементы являются хешируемыми объектами (как в данном случае со строками), то вы можете использовать set intersection:

 >>> list1 = ['B', 'C', 'D']
>>> list2 = [['1', 'A'], ['2', 'B'], ['3', 'D'], ['5', 'C']]

>>> s = set(list1)
>>> [l for l in list2 if set(l) amp; s]
[['2', 'B'], ['3', 'D'], ['5', 'C']]
  

Если пересечение пустое, то это обрабатывается как значение false для целей if фильтрации в понимании списка.

Тем не менее, я не могу воспроизвести тот факт, что ваш (первый) код в вопросе не работает для вас; он отлично работает, когда я пытаюсь это сделать. Ваш второй фрагмент кода (помимо опечатки) имеет потенциальную проблему с дублированием подсписков в выходных данных, потому что вы не break делаете этого из внутреннего цикла после нахождения первого соответствующего элемента.