web-dev-qa-db-fra.com

Rechercher des éléments non communs dans les listes

J'essaie d'écrire un morceau de code qui peut automatiquement factoriser une expression. Par exemple, Si j'ai deux listes [1,2,3,4] et [2,3,5], le code devrait pouvoir trouver les éléments communs dans les deux listes, [2,3], et combinez le reste des éléments dans une nouvelle liste, soit [1,4,5]. 

De ce post: Comment trouver l'intersection de la liste? Je vois que les éléments communs peuvent être trouvés par 

set([1,2,3,4]&set([2,3,5]). 

Existe-t-il un moyen simple de récupérer des éléments non communs de chaque liste, dans mon exemple, [1,4] et [5]?

Je peux aller de l'avant et faire une boucle for:

lists = [[1,2,3,4],[2,3,5]]
conCommon = []
common = [2,3]
for elem in lists:
    for elem in eachList:
    if elem not in common:
        nonCommon += elem

Mais cela semble redondant et inefficace. Python fournit-il une fonction pratique qui peut le faire? Merci d'avance!!

22
turtlesoup

Utilisez l'opérateur de différence symétrique pour sets (autrement dit l'opérateur XOR):

>>> set([1,2,3]) ^ set([3,4,5])
set([1, 2, 4, 5])
45
Amber

Vous pouvez utiliser le concept Intersection pour traiter ce type de problèmes.

b1 = [1,2,3,4,5,9,11,15]
b2 = [4,5,6,7,8]
set(b1).intersection(b2)
Out[22]: {4, 5}

La meilleure chose à propos de l'utilisation de ce code est qu'il fonctionne assez rapidement pour les grandes données. J'ai b1 avec 607139 et b2 avec 296029 éléments lorsque j'utilise cette logique, j'obtiens mes résultats en 2,9 secondes. 

12
saimadhu.polamuri

Ancienne question, mais on dirait que python a une fonction intégrée qui fournit exactement ce que vous recherchez: .difference().

EXEMPLE

list_one = [1,2,3,4]
list_two = [2,3,5]

one_not_two = set(list_one).difference(list_two)
# set([1, 4])

two_not_one = set(list_two).difference(list_one)
# set([5])

Cela pourrait aussi être écrit comme:

one_not_two = set(list_one) - set(list_two)

Calendrier

J'ai fait quelques tests de chronométrage sur les deux et il semble que .difference() ait un léger bord, de 10 à 15%, mais chaque méthode prenait environ un huitième de seconde pour filtrer les 1M éléments (nombres entiers aléatoires entre 500 et 100 000), donc à moins que vous êtes très sensible au temps, c'est probablement immatériel.

Autres notes

Il semble que le PO recherche une solution fournissant deux listes (ou ensembles) distincts - la première contenant des éléments qui ne figurent pas dans la seconde, et inversement. La plupart des réponses précédentes renvoient une seule liste ou un ensemble comprenant tous les éléments.

La question se pose également de savoir si les éléments susceptibles d'être dupliqués dans la première liste doivent être comptés plusieurs fois, ou une seule fois.

Si le PO veut conserver des doublons, une liste de compréhension peut être utilisée, par exemple: 

one_not_two = [ x for x in list_one if x not in list_two ]
two_not_one = [ x for x in list_two if x not in list_one ]

... ce qui est à peu près la même solution que celle posée dans la question initiale, mais un peu plus propre. Cette méthode permet de conserver les doublons de la liste d'origine, mais elle est considérablement (comme de multiples ordres de grandeur) plus lente pour les ensembles de données plus volumineux.

1
elPastor

Vous pouvez utiliser la méthode d'attribut .__xor__

set([1,2,3,4]).__xor__(set([2,3,5]))

ou 

a = set([1,2,3,4])
b = set([2,3,5])
a.__xor__(b)
0
SuperNova