Python: проверьте, находится ли вложенный список во вложенном списке

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

Скажем, у меня есть следующий смешанный вложенный список в python:

a = [((1,1),(0,0)), (3,4)]

Я хотел бы проверить, появляются ли следующие кортежи b, c и d в a:

b = (1,1)
c = (0,0)
d = (3,4)

print(b in a)  # <- False ?
print(c in a)  # <- False ?
print(d in a)  # <- True

Я хотел бы заменить код в каждом операторе печати таким образом, чтобы поиск находил кортеж в списке и как таковой возвращал True

Любая помощь вообще будет высоко оценена. Извините, если этот вопрос уже задавался ранее.


person Sayshi    schedule 20.04.2018    source источник
comment
произвольна ли глубина вложенности? или будет максимум, скажем, 2?   -  person Ma0    schedule 20.04.2018
comment
сначала у вас есть список вложенных кортежей, а не вложенных списков в вашем примере: D   -  person Drako    schedule 20.04.2018
comment
Я рекомендую сначала зайти на python.org — прочитать некоторые документы о типах python и т. д.   -  person Drako    schedule 20.04.2018
comment
они правильные, потому что в a нет (1,1), в a есть кортеж ((1,1),(0,0))   -  person Drako    schedule 20.04.2018
comment
вы можете сделать: для элемента в проверке, если x в элементе получить True для ваших случаев (но, как спросил @Ev. Kounis - необходимо учитывать глубину   -  person Drako    schedule 20.04.2018
comment
также вложенные списки будут выглядеть так: a = [[[1,1],[0,0]], [3,4]]   -  person Drako    schedule 20.04.2018
comment
Вы должны реализовать это самостоятельно. Для этого нет встроенного Python. Затем, вы боретесь с его реализацией (если да, то как?)   -  person user202729    schedule 20.04.2018
comment
Я предполагаю, что рекурсивный подход был бы лучше, если бы глубина не была известна.   -  person BcK    schedule 20.04.2018


Ответы (3)


Нам нужна рекурсивная функция, которая принимает список или кортеж и элемент для поиска.

Каждая функция должна проверять, находится ли элемент в текущей итерации, используя оператор in. Если он есть, верните True, в противном случае проверьте, находится ли он в каком-либо из нижних измерений, рекурсивно вызвав себя с каждой из нижних итераций, и верните, если какой-либо из них завершился успешно (это можно сделать с помощью for-loop, но мы также можем используйте функцию any()).

Таким образом, один лайнер будет примерно:

def inc(it, e):
    return True if e in it else any(inc(iit, e) for iit in it if type(iit) in (list, tuple))

И работает как задумано:

>>> inc(a, (1,1))
True
>>> inc(a, (0,0))
True
>>> inc(a, (3,4))
True
person Joe Iddon    schedule 20.04.2018
comment
Мне нравится использование any, но я думаю, что использование условного выражения делает это слишком громоздким, я бы просто сделал if: ... else:... и сохранил ваше any. Вы определенно должны использовать isinstance, хотя... - person juanpa.arrivillaga; 20.04.2018

Список состоит из двух элементов: кортежа, который содержит другие кортежи, и кортежа целых чисел. Если вы хотите проверить вложенные структуры, вам придется сделать это самостоятельно. Рекурсивное решение (это предполагает, что вложенными контейнерами могут быть только кортежи или списки) будет одним из вариантов, если вложенность может быть произвольно глубокой:

>>> a = [((1,1),(0,0)), (3,4)]
>>> def is_in(x, nested):
...     result = False
...     if not isinstance(nested, (tuple, list)):
...         return result
...     for item in nested:
...         if x == item:
...             result = True
...         else:
...             result = result or is_in(x, item)
...         if result:
...             return True
...     return result
...
>>> is_in((1,1), a)
True
>>> is_in((0,0), a)
True
>>> is_in((3,4), a)
True
>>> is_in((8, 8), a)
False
>

Это должно прекратить обход, как только будет найдено первое совпадение.

Обратите внимание: если вам не нравится рекурсия, вы можете заменить стек вызовов своим собственным стеком!

def is_in_iterative(x, nested):
    stack = [nested]
    while stack:
        item = stack.pop()
        print(item)
        if item == x:
            return True
        elif isinstance(item, (list, tuple)):
            stack.extend(item)
    return False

Однако обратите внимание, что это будет проверяться в обратном порядке...

person juanpa.arrivillaga    schedule 20.04.2018
comment
Рекурсия определенно является хорошим решением для этого. Однако логику можно записать короче: def is_in(x, вложенный): если не isinstance(вложенный, (кортеж, список)): вернуть False, если x во вложенном: вернуть True для элемента во вложенном: вернуть is_in(x, элемент) вернуть ложь - person Lukisn; 20.04.2018
comment
@Lukisn почти уверен, что это не проверит весь подсписок, так как вы вернетесь на первую итерацию цикла for, но я не могу точно сказать, что вы имеете в виду, без отступа. Итак, рассмотрим a = [((1, 1), (0, 0)), (3, 4), ((8, 8), 10)] и is_in((8,8), a) - person juanpa.arrivillaga; 20.04.2018

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

a = [((1,1),(0,0)), (3,4)]
global bb
bb=False

def checker(tuple1, tuple2):
    b=str(type(('a','b')))
    for i in range(len(tuple1)):
        if(str(type(tuple1[i]))!=b):
            if (tuple1==tuple2):
                global bb
                bb=True


        else:
            checker(tuple1[i],tuple2)

checker(a,(1,1))
print(bb)
#-->True

bb=False
checker(a,(3,4))
print(bb)
#-->True

bb=False
checker(a,(0,0))
print(bb)
#--->True

bb=False
checker(a,(10,1))
print(bb)
#--->False
person M.H Mighani    schedule 20.04.2018