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:
Quelle serait la solution optimale compte tenu du scénario?
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.
>>> 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
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.
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.
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é.
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)
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
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).
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é.
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
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))
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)