web-dev-qa-db-fra.com

Vérifier si un élément est dans une liste imbriquée

dans une simple liste, la vérification suivante est triviale:

x = [1, 2, 3]

2 in x  -> True

mais s'il s'agit d'une liste de liste, telle que:

x = [[1, 2, 3], [2, 3, 4]]

2 in x   -> False

comment peut-on résoudre ce problème afin de renvoyer True?

9
Al_Iskander

Essayez ceci en utilisant la fonction any intégrée. C'est la solution la plus idiomatique, mais aussi efficace, car any court-circuite et s'arrête dès que la première correspondance est trouvée:

x = [[1, 2, 3], [2, 3, 4]]
any(2 in sl for sl in x)
=> True
9
Óscar López

Voici une version récursive qui fonctionne pour tous les niveaux d'imbrication.

def in_nested_list(my_list, item):
    """
    Determines if an item is in my_list, even if nested in a lower-level list.
    """
    if item in my_list:
        return True
    else:
        return any(in_nested_list(sublist, item) for sublist in my_list if isinstance(sublist, list))

Voici quelques tests:

x = [1, 3, [1, 2, 3], [2, 3, 4], [3, 4, [], [2, 3, 'a']]]
print in_nested_list(x, 2)
print in_nested_list(x, 5)
print in_nested_list(x, 'a')
print in_nested_list(x, 'b')
print in_nested_list(x, [])
print in_nested_list(x, [1, 2])
print in_nested_list(x, [1, 2, 3])

True
False
True
False
True
False
True
8
Curt F.

Vous pouvez utiliser set.issubset() et itertools.chain():

In [55]: x = [[1, 2, 3], [2, 3, 4]]

In [56]: {4}.issubset(chain.from_iterable(x))
Out[56]: True

In [57]: {10}.issubset(chain.from_iterable(x))
Out[57]: False

Vous pouvez également contrôler efficacement l'adhésion de plusieurs éléments:

In [70]: {2, 4}.issubset(chain.from_iterable(x))
Out[70]: True

In [71]: {2, 4, 10}.issubset(chain.from_iterable(x))
Out[71]: False
4
Kasrâmvd

Cela fonctionnerait:

for arr in x:
    if 2 in arr:
        print True
        break

Je recommanderais la réponse d'Oscar, car any est la bonne option ici.

2
KVISH

TL; DR

x = [0, [1, 2, 3], [2, 3, [4, 5, [6], []], [7, 8]]]
def find_n(input_list, n):
    for el in input_list:
        if el == n or (isinstance(el, list) and find_n(el, n)):
            return True
    return False
print(find_n(x, 6))

Notez que, assez intéressant:

def find_n(input_list, n):
    return any([el == n or (isinstance(el, list) and find_n(el, n)) for el in input_list])
return (find_n(x, 6))

Est plus de 50% plus lent à exécuter.

Réponse originale (s)

Que faire si vous avez une profondeur supérieure à 2? Voici une approche du cas générique:

x = [0, [1, 2, 3], [2, 3, [4, 5, [6], []], [7, 8]]]

def flatten(input_list):
    flat_list = []
    for sublist_or_el in input_list:
        if isinstance(sublist_or_el, list):
            for sublist_or_el2 in flatten(sublist_or_el):
                flat_list.append(sublist_or_el2)
        else:
            flat_list.append(sublist_or_el)
    return flat_list

print(6 in flatten(x))

Pas sûr de la vitesse, mais comme je l’ai dit, c’est une approche qui peut être utile à quelqu'un!

MODIFIER - MEILLEURE (PLUS RAPIDE) RÉPONSE:

Cela réduit le temps pris (si n est trouvé, même si on ne le trouve pas, environ la moitié du temps réellement ...) en revenant plus tôt. Ceci est légèrement plus rapide que la réponse de @Curt F., et plus lent que la création d'une fonction supposant une profondeur maximale de 2 (la réponse acceptée).

x = [0, [1, 2, 3], [2, 3, [4, 5, [6], []], [7, 8]]]
def find_n(input_list, n):
    flat_list = []
    for sublist_or_el in input_list:
        if isinstance(sublist_or_el, list):
            if find_n(sublist_or_el, n) == True:
                return True
        Elif sublist_or_el == n:
            return True
    return False
print(find_n(x, 6))

Timing rapide (très hacky, désolé, occupé aujourd'hui!):

import time

x = [0, [1, 2, 3], [2, 3, [4, 5, [6], []], [7, 8]]]

def a():
    def flatten(input_list):
        flat_list = []
        for sublist_or_el in input_list:
            if isinstance(sublist_or_el, list):
                for sublist_or_el2 in flatten(sublist_or_el):
                    flat_list.append(sublist_or_el2)
            else:
                flat_list.append(sublist_or_el)
        return flat_list
    return (6 in flatten(x))

def b():
    def find_n(input_list, n):
        flat_list = []
        for sublist_or_el in input_list:
            if isinstance(sublist_or_el, list):
                if find_n(sublist_or_el, n) == True:
                    return True
            Elif sublist_or_el == n:
                return True
        return False
    return (find_n(x, 6))


zz = 0
for i in range(100000):
    start_time = time.clock()
    res = a()
    zz += time.clock() - start_time
print(a())
print((zz)/100, "seconds")

zz = 0
for i in range(100000):
    start_time = time.clock()
    res = b()
    zz += time.clock() - start_time
print(b())
print((zz)/100, "seconds")
1
Eugene

Mon code est basé sur la solution d'Óscar López. Sa solution n'était pas exactement ce dont j'avais besoin pour résoudre mon problème, mais elle me donnait suffisamment d'informations pour comprendre mon problème. Donc, si vous avez des éléments imbriqués dans une liste et que vous avez besoin de voir s'ils sont dans une autre liste imbriquée, cela fonctionnera.

#!python2

lst1 = [['a', '1'], ['b', '2'], ['c', '3'], ['d', '4'], ['e', '5']]
lst2 = [['b', '2'], ['d', '4'], ['f', '6'], ['h', '8'], ['j', '10'], ['l', '12'], ['n', '14']]

# comparing by index 0, prints lst1 items that aren't in lst2
for i in lst1:
    if not any(i[0] in sublst for sublst in lst2):
        print i
'''
['a', '1']
['c', '3']
['e', '5']
'''

print

# comparing by index 0, prints lst2 items that aren't in lst1
for i in lst2:
    if not any(i[0] in sublst for sublst in lst1):
        print i
'''
['f', '6']
['h', '8']
['j', '10']
['l', '12']
['n', '14']
'''
0
Michael Swartz

essayer 

 2 in [i for sublist in x  for i in sublist]
0
Afsal Salim