web-dev-qa-db-fra.com

Vérifier la présence d'une liste découpée en tranches en Python

Je veux écrire une fonction qui détermine si une sous-liste existe dans une liste plus grande. 

list1 = [1,0,1,1,1,0,0]
list2 = [1,0,1,0,1,0,1]

#Should return true
sublistExists(list1, [1,1,1])

#Should return false
sublistExists(list2, [1,1,1])

Existe-t-il une fonction Python capable de le faire?

34
Jonathan

Si vous êtes certain que vos entrées ne contiendront que les chiffres uniques 0 et 1, vous pouvez convertir en chaînes:

def sublistExists(list1, list2):
    return ''.join(map(str, list2)) in ''.join(map(str, list1))

Cela crée deux chaînes, ce n'est donc pas la solution la plus efficace, mais comme il tire parti de l'algorithme de recherche de chaînes optimisé de Python, il est probablement suffisant pour la plupart des applications.

Si l'efficacité est très importante, vous pouvez utiliser l'algorithme de recherche de chaînes Boyer-Moore , adapté au travail sur les listes.

Une recherche naïve a O (n * m) le pire des cas, mais peut convenir si vous ne pouvez pas utiliser le tour de conversion en chaîne et que vous n'avez pas à vous soucier des performances.

19
Mark Byers

Soyons un peu fonctionnels, allons-nous? :)

def contains_sublist(lst, sublst):
    n = len(sublst)
    return any((sublst == lst[i:i+n]) for i in xrange(len(lst)-n+1))

Notez que any() s'arrêtera lors du premier match de sous-match dans lst - ou échouera s'il n'y a pas de correspondance, après O (m * n) ops

40
Nas Banov

Aucune fonction que je connaisse

def sublistExists(list, sublist):
    for i in range(len(list)-len(sublist)+1):
        if sublist == list[i:i+len(sublist)]:
            return True #return position (i) if you wish
    return False #or -1

Comme Mark l’a noté, ce n’est pas la recherche la plus efficace (c’est O (n * m)). Ce problème peut être abordé de la même manière que la recherche de chaînes.

4
sas4740

Le moyen le plus efficace consiste à utiliser l’algorithme de Boyer-Moore , comme le suggère Mark Byers. Je l'ai déjà fait ici: Boyer-Moore recherche une liste pour une sous-liste en Python , mais je vais coller le code ici. Il est basé sur l'article de Wikipedia.

La fonction search() renvoie l'index de la sous-liste recherchée ou -1 en cas d'échec.

def search(haystack, needle):
    """
    Search list `haystack` for sublist `needle`.
    """
    if len(needle) == 0:
        return 0
    char_table = make_char_table(needle)
    offset_table = make_offset_table(needle)
    i = len(needle) - 1
    while i < len(haystack):
        j = len(needle) - 1
        while needle[j] == haystack[i]:
            if j == 0:
                return i
            i -= 1
            j -= 1
        i += max(offset_table[len(needle) - 1 - j], char_table.get(haystack[i]));
    return -1


def make_char_table(needle):
    """
    Makes the jump table based on the mismatched character information.
    """
    table = {}
    for i in range(len(needle) - 1):
        table[needle[i]] = len(needle) - 1 - i
    return table

def make_offset_table(needle):
    """
    Makes the jump table based on the scan offset in which mismatch occurs.
    """
    table = []
    last_prefix_position = len(needle)
    for i in reversed(range(len(needle))):
        if is_prefix(needle, i + 1):
            last_prefix_position = i + 1
        table.append(last_prefix_position - i + len(needle) - 1)
    for i in range(len(needle) - 1):
        slen = suffix_length(needle, i)
        table[slen] = len(needle) - 1 - i + slen
    return table

def is_prefix(needle, p):
    """
    Is needle[p:end] a prefix of needle?
    """
    j = 0
    for i in range(p, len(needle)):
        if needle[i] != needle[j]:
            return 0
        j += 1    
    return 1

def suffix_length(needle, p):
    """
    Returns the maximum length of the substring ending at p that is a suffix.
    """
    length = 0;
    j = len(needle) - 1
    for i in reversed(range(p + 1)):
        if needle[i] == needle[j]:
            length += 1
        else:
            break
        j -= 1
    return length

Voici l'exemple de la question:

def main():
    list1 = [1,0,1,1,1,0,0]
    list2 = [1,0,1,0,1,0,1]
    index = search(list1, [1, 1, 1])
    print(index)
    index = search(list2, [1, 1, 1])
    print(index)

if __== '__main__':
    main()

Sortie:

 2 
 - 1 
2
def sublistExists(x, y):
  occ = [i for i, a in enumerate(x) if a == y[0]]
  for b in occ:
      if x[b:b+len(y)] == y:
           print 'YES-- SUBLIST at : ', b
           return True
      if len(occ)-1 ==  occ.index(b):
           print 'NO SUBLIST'
           return False

list1 = [1,0,1,1,1,0,0]
list2 = [1,0,1,0,1,0,1]

#should return True
sublistExists(list1, [1,1,1])

#Should return False
sublistExists(list2, [1,1,1])
1
SuperNova

Voici un moyen qui fonctionnera pour des listes simples qui est légèrement moins fragile que Mark

def sublistExists(haystack, needle):
    def munge(s):
        return ", "+format(str(s)[1:-1])+","
    return munge(needle) in munge(haystack)
1
John La Rooy

Peut-être aussi jeter une version récursive de la solution de @ NasBanov

def foo(sub, lst):
    '''Checks if sub is in lst.

    Expects both arguments to be lists
    '''
    if len(lst) < len(sub):
        return False
    return sub == lst[:len(sub)] or foo(sub, lst[1:])
0
wwii
def sublist(l1,l2):
  if len(l1) < len(l2):
    for i in range(0, len(l1)):
      for j in range(0, len(l2)):
        if l1[i]==l2[j] and j==i+1:
        pass
      return True
  else:
    return False
0
Ashutosh K Singh