web-dev-qa-db-fra.com

Python - vérifier si une liste est un sous-ensemble de l'autre

Je dois vérifier si une liste est un sous-ensemble d'un autre - un retour booléen est tout ce que je recherche.
Tester l’égalité sur la liste plus petite après une intersection est-il le moyen le plus rapide de procéder?
La performance est de la plus haute importance compte tenu de la quantité de jeux de données à comparer.
Ajouter d’autres faits sur la base des discussions: 

  1. L'une des listes sera-t-elle la même pour de nombreux tests?
    C'est l'un des tableaux statiques 
  2. Cela doit-il être une liste?
    Ce n'est pas le cas - la table de consultation statique peut être celle qui fonctionne le mieux.
    Le dynamique est un dict dont nous extrayons les clés pour effectuer une recherche statique. 

Quelle serait la solution optimale compte tenu du scénario?

130
IUnknown

La fonction performante fournie par Python est set.issubset . Il y a quelques restrictions qui rendent difficile de savoir si c'est la réponse à votre question, cependant.

Une liste peut contenir des éléments plusieurs fois et correspond à un ordre spécifique. Un ensemble n'en a pas. Pour obtenir des performances élevées, utilisez uniquement les objets hashable

Voulez-vous parler d'un sous-ensemble ou d'une sous-séquence (ce qui signifie que vous souhaiterez un algorithme de recherche de chaîne)? L'une des listes sera-t-elle la même pour de nombreux tests? Quels sont les types de données contenus dans la liste? Et d'ailleurs, faut-il une liste? 

Votre autre article intersectez un dict et une liste a clarifié les types et vous a recommandé d’utiliser les vues clés du dictionnaire pour leur fonctionnalité. Dans ce cas, il était connu pour fonctionner parce que les clés de dictionnaire se comportaient comme un ensemble (à tel point qu'avant d'avoir des ensembles en Python, nous utilisions des dictionnaires). On se demande comment la question est devenue moins précise en trois heures. 

96
Yann Vernier
>>> a = [1, 3, 5]
>>> b = [1, 3, 5, 8]
>>> c = [3, 5, 9]
>>> set(a) <= set(b)
True
>>> set(c) <= set(b)
False

>>> a = ['yes', 'no', 'hmm']
>>> b = ['yes', 'no', 'hmm', 'well']
>>> c = ['sorry', 'no', 'hmm']
>>> 
>>> set(a) <= set(b)
True
>>> set(c) <= set(b)
False
88
Yulan Liu
one = [1, 2, 3]
two = [9, 8, 5, 3, 2, 1]

all(x in two for x in one)

Explication: Le générateur crée des booléens en parcourant la liste one en vérifiant si cet élément est dans la liste two. all() retourne True si chaque élément est véridique, sinon False

Il y a également un avantage à ce que all renvoie False à la première instance d'un élément manquant au lieu de devoir traiter chaque élément. 

29
voidnologo

En supposant que les articles sont lavables

>>> from collections import Counter
>>> not Counter([1, 2]) - Counter([1])
False
>>> not Counter([1, 2]) - Counter([1, 2])
True
>>> not Counter([1, 2, 2]) - Counter([1, 2])
False

Si vous ne vous souciez pas des éléments en double, par exemple. [1, 2, 2] et [1, 2] puis utilisez simplement:

>>> set([1, 2, 2]).issubset([1, 2])
True

Est-ce que le test le plus rapide de l'égalité consiste à tester l'égalité sur la liste plus petite après une intersection?

.issubset sera le moyen le plus rapide de le faire. Vérifier la longueur avant de tester issubset n'améliorera pas la vitesse, car vous avez toujours des éléments O (N + M) à parcourir et à vérifier. 

18
jamylak

Je sais que c'est tard, mais je voulais juste mettre à jour la réponse avec ce qui a fonctionné pour moi (Python 3)

# var 1
x = [1,2,3,4]
#  var 2
y = [1,2]

# check if var2 is subset of var1
all([z in x for z in y])

À votre santé.

3
Mohit

Une autre solution consisterait à utiliser une variable intersection.

one = [1, 2, 3]
two = [9, 8, 5, 3, 2, 1]

set(one).intersection(set(two)) == set(one)

L'intersection des ensembles contiendrait de set one

(OU)

one = [1, 2, 3]
two = [9, 8, 5, 3, 2, 1]

set(one) & (set(two)) == set(one)
3
SuperNova

La théorie des ensembles est inappropriée pour les listes car les doublons donneront des réponses erronées en utilisant la théorie des ensembles. 

Par exemple:

a = [1, 3, 3, 3, 5]
b = [1, 3, 3, 4, 5]
set(b) > set(a)

n'a pas de sens. Oui, cela donne une fausse réponse mais ce n’est pas correct car la théorie des ensembles n’est qu’une comparaison: 1,3,5 contre 1,3,4,5. Vous devez inclure tous les doublons.

Au lieu de cela, vous devez compter chaque occurrence de chaque élément et en faire un plus grand que égal à vérifier. Ce n'est pas très coûteux, car il n'utilise pas d'opérations O (N ^ 2) et ne nécessite pas de tri rapide.

#!/usr/bin/env python

from collections import Counter

def containedInFirst(a, b):
  a_count = Counter(a)
  b_count = Counter(b)
  for key in b_count:
    if a_count.has_key(key) == False:
      return False
    if b_count[key] > a_count[key]:
      return False
  return True


a = [1, 3, 3, 3, 5]
b = [1, 3, 3, 4, 5]
print "b in a: ", containedInFirst(a, b)

a = [1, 3, 3, 3, 4, 4, 5]
b = [1, 3, 3, 4, 5]
print "b in a: ", containedInFirst(a, b)

Ensuite, en cours d'exécution, vous obtenez:

$ python contained.py 
b in a:  False
b in a:  True
1
Eamonn Kenny
one = [1, 2, 3]
two = [9, 8, 5, 3, 2, 1]

set(x in two for x in one) == set([True])

Si list1 est dans la liste 2:

  • (x in two for x in one) génère une liste de True

  • quand on fait un set(x in two for x in one) n'a qu'un seul élément (True).

1
SuperNova

Essayez bitwise ET

>>> set([1,2]) & set([1,2,3])
set([1, 2])
>>> set([0]) & set([1,2,3])
set([])

Je ne l'ai pas encore profilé.

1
hjbolide

Voici comment savoir si une liste est un sous-ensemble d’une autre, la séquence m’importe dans mon cas.

def is_subset(list_long,list_short):
    short_length = len(list_short)
    subset_list = []
    for i in range(len(list_long)-short_length+1):
        subset_list.append(list_long[i:i+short_length])
    if list_short in subset_list:
        return True
    else: return False
0
Mindee

Dans Python 3.5, vous pouvez utiliser une [*set()][index] pour obtenir l'élément. C'est une solution beaucoup plus lente que les autres méthodes.

one = [1, 2, 3]
two = [9, 8, 5, 3, 2, 1]

result = set(x in two for x in one)

[*result][0] == True

ou juste avec len et set

len(set(a+b)) == len(set(a))
0
SuperNova

Le code ci-dessous vérifie si un ensemble donné est un "sous-ensemble approprié" d'un autre ensemble 

 def is_proper_subset(set, superset):
     return all(x in superset for x in set) and len(set)<len(superset)
0
Leo Bastin