Je dois comparer deux listes afin de créer une nouvelle liste d'éléments spécifiques trouvés dans une liste mais pas dans l'autre. Par exemple:
main_list=[]
list_1=["a", "b", "c", "d", "e"]
list_2=["a", "f", "c", "m"]
Je veux parcourir list_1 et ajouter à main_list tous les éléments de list_2 qui ne figurent pas dans list_1.
Le résultat devrait être:
main_list=["f", "m"]
Comment puis-je le faire avec python?
(1) Vous pouvez utiliser setdiff1d
de NumPy. Parmi les réponse de Chinny84 , si vous êtes concerné par les éléments uniques , alors:
_import numpy as np
list_1 = ["a", "b", "c", "d", "e"]
list_2 = ["a", "f", "c", "m"]
main_list = np.setdiff1d(list_2,list_1)
_
(2) Sinon, utilisez main_list = np.setdiff1d(list_2,list_1, assume_unique=True)
Les deux réponses vous donneront _["f", "m"]
_. Toutefois, si _list_2 = ["a", "f", "c", "m", "m"]
_, answer (1) donne _["f", "m"]
_ MAIS answer (2) donne _["f", "m", "m"]
_ (car l'unicité de chaque élément de _list_2
_ est indifférente).
Vous pouvez utiliser des ensembles:
main_list = list(set(list_2) - set(list_1))
Sortie:
>>> list_1=["a", "b", "c", "d", "e"]
>>> list_2=["a", "f", "c", "m"]
>>> set(list_2) - set(list_1)
set(['m', 'f'])
>>> list(set(list_2) - set(list_1))
['m', 'f']
D'après le commentaire de @JonClements, voici une version plus ordonnée:
>>> list_1=["a", "b", "c", "d", "e"]
>>> list_2=["a", "f", "c", "m"]
>>> list(set(list_2).difference(list_1))
['m', 'f']
Vous ne savez pas pourquoi les explications ci-dessus sont si compliquées quand vous avez des méthodes natives disponibles:
main_list = list(set(list_2)-set(list_1))
Utilisez un compréhension de la liste comme ceci:
main_list = [item for item in list_2 if item not in list_1]
Sortie:
>>> list_1 = ["a", "b", "c", "d", "e"]
>>> list_2 = ["a", "f", "c", "m"]
>>>
>>> main_list = [item for item in list_2 if item not in list_1]
>>> main_list
['f', 'm']
Modifier:
Comme mentionné dans les commentaires ci-dessous, avec les grandes listes, ce qui précède n'est pas la solution idéale. Dans ce cas, une meilleure option serait de convertir list_1
en set
en premier:
set_1 = set(list_1) # this reduces the lookup time from O(n) to O(1)
main_list = [item for item in list_2 if item not in set_1]
Si vous voulez une solution à une ligne (ignorant les importations) ne nécessitant que O(max(n, m))
travail pour les entrées de longueur n
et m
, pas O(n * m)
travail, vous pouvez le faire avec le module itertools
:
from itertools import filterfalse
main_list = list(filterfalse(set(list_1).__contains__, list_2))
Cela tire parti des fonctions fonctionnelles prenant une fonction de rappel lors de la construction, ce qui lui permet de créer le rappel une fois et de le réutiliser pour chaque élément sans avoir à le stocker quelque part (car filterfalse
le stocke en interne); Les compréhensions de liste et les expressions génératrices peuvent faire cela, mais c'est moche †
Cela donne les mêmes résultats en une seule ligne comme:
main_list = [x for x in list_2 if x not in list_1]
avec la vitesse de:
set_1 = set(list_1)
main_list = [x for x in list_2 if x not in set_1]
Bien sûr, si les comparaisons sont destinées à être positionnelles, alors:
list_1 = [1, 2, 3]
list_2 = [2, 3, 4]
devrait produire:
main_list = [2, 3, 4]
(parce que la valeur dans list_2
a une correspondance au même index que dans list_1
), vous devez absolument aller avec la réponse de Patrick , ce qui n'implique aucun temporaire list
s ou set
s (même si set
s étant à peu près O(1)
, ils ont un facteur "constant" par contrôle plus élevé que les simples contrôles d'égalité) et impliquent un travail O(min(n, m))
inférieur à toute autre réponse, et si votre problème est sensible à la position, est la seule solution correcte lorsque les éléments correspondants apparaissent avec des décalages incompatibles.
†: La manière de faire la même chose avec une compréhension de liste qu'un one-liner serait d'utiliser la boucle imbriquée pour créer et mettre en cache des valeurs dans la boucle "la plus à l'extérieur", par exemple:
main_list = [x for set_1 in (set(list_1),) for x in list_2 if x not in set_1]
ce qui offre également un avantage mineur en termes de performances sur Python 3 (car à présent set_1
est localement défini dans le code de compréhension, plutôt que recherché à partir de la portée imbriquée pour chaque contrôle; sur Python 2 cela n'a pas d'importance, car Python 2 n'utilise pas de fermetures pour la compréhension de liste, elles fonctionnent dans le même champ d'application).
main_list=[]
list_1=["a", "b", "c", "d", "e"]
list_2=["a", "f", "c", "m"]
for i in list_2:
if i not in list_1:
main_list.append(i)
print(main_list)
sortie:
['f', 'm']
Je voudrais Zip
les listes ensemble pour les comparer élément par élément.
main_list = [b for a, b in Zip(list1, list2) if a!= b]
Si le nombre d'occurrences doit être pris en compte, vous devrez probablement utiliser quelque chose comme collections.Counter
:
list_1=["a", "b", "c", "d", "e"]
list_2=["a", "f", "c", "m"]
from collections import Counter
cnt1 = Counter(list_1)
cnt2 = Counter(list_2)
final = [key for key, counts in cnt2.items() if cnt1.get(key, 0) != counts]
>>> final
['f', 'm']
Comme promis, cela peut également traiter un nombre différent d'occurrences en tant que "différence":
list_1=["a", "b", "c", "d", "e", 'a']
cnt1 = Counter(list_1)
cnt2 = Counter(list_2)
final = [key for key, counts in cnt2.items() if cnt1.get(key, 0) != counts]
>>> final
['a', 'f', 'm']
À partir de ser1, supprimez les éléments présents dans ser2.
ser1 = pd.Series ([1, 2, 3, 4, 5]) ser2 = pd.Series ([4, 5, 6, 7, 8])
ser1 [~ ser1.isin (ser2)]