Comparaison des éléments communs entre 2 listes

143
def common_elements(list1, list2):
    """
    Return a list containing the elements which are in both list1 and list2

    >>> common_elements([1,2,3,4,5,6], [3,5,7,9])
    [3, 5]
    >>> common_elements(['this','this','n','that'],['this','not','that','that'])
    ['this', 'that']
    """
    for element in list1:
        if element in list2:
            return list(element)

Je l'ai jusqu'à présent, mais je n'arrive pas à le faire fonctionner!

Des idées?

Daniel
la source
1
Bonjour, pourriez-vous ajouter quelques détails sur la manière dont vous prévoyez d'utiliser le code? Si c'est pour terminer une mission, il peut être préférable de choisir une solution qui encapsule la voie «pythonique». Cependant, si l'efficacité est votre préoccupation, alors la méthode «pythonique» ne sera probablement pas la solution la plus efficace. En nous informant de ces détails, les solutions visent à résoudre votre problème.
Matt C

Réponses:

278
>>> list1 = [1,2,3,4,5,6]
>>> list2 = [3, 5, 7, 9]
>>> list(set(list1).intersection(list2))
[3, 5]
SilentGhost
la source
1
+1 mais personnellement, j'avais utilisé frozenset car il est immuable et peut donc être utilisé comme clé de dictionnaire, etc.
zebrabox
19
Cela renverra les éléments / unique / common, mais pas les éléments répétés qui peuvent exister.
Dologan
@SilentGhost. Comment obtenir le nombre d'éléments correspondants à partir de deux listes. Dans ce cas, il est 2.
Poka
@Poka len (list (set (list1) .intersection (list2)))
Dharmanshu Kamra
2
FYI. C'est définitivement plus rapide que la solution proposée par Tamás, mais pour le cas d'utilisation que je regardais lorsque je me suis retrouvé sur cette page, il était important de conserver l'ordre d'origine des éléments pour les éléments post-filtrés. Cette méthode perd l'ordre, tandis que la méthode de compréhension de liste préserve l'ordre. Important si quelqu'un a besoin d'en tenir compte. Merci.
agftrading
41

Vous pouvez également utiliser des ensembles et obtenir les points communs sur une seule ligne: soustrayez l'ensemble contenant les différences de l'un des ensembles.

A = [1,2,3,4]
B = [2,4,7,8]
commonalities = set(A) - (set(A) - set(B))
Au-delà de Rubicon
la source
4
Cela convertit A en deux fois, un gaspillage inutile.
wim
36

Les solutions suggérées par S.Mark et SilentGhost vous indiquent généralement comment cela doit être fait de manière pythonique, mais j'ai pensé que vous pourriez également bénéficier de savoir pourquoi votre solution ne fonctionne pas. Le problème est que dès que vous trouvez le premier élément commun dans les deux listes, vous ne retournez que cet élément unique. Votre solution pourrait être corrigée en créant une resultliste et en collectant les éléments communs de cette liste:

def common_elements(list1, list2):
    result = []
    for element in list1:
        if element in list2:
            result.append(element)
    return result

Une version encore plus courte utilisant des compréhensions de liste:

def common_elements(list1, list2):
    return [element for element in list1 if element in list2]

Cependant, comme je l'ai dit, c'est une façon très inefficace de faire cela - les types d'ensemble intégrés de Python sont beaucoup plus efficaces car ils sont implémentés en C en interne.

Tamás
la source
1
Idéal pour les deux propositions
dlewin
1
REMARQUE: les méthodes ci-dessus ne fonctionneront que pour les listes de taille égale. Si vous travaillez avec des listes de tailles inégales, comme je le suis, vous devrez évaluer l'ordre basé sur len () avant d'appeler la fonction: list1 = [2,2,2], list2 [2,3] -> [2,2,2] list1 = [2,3], list2 [2,2,2] -> [2]
redthumb
29

utiliser définir les intersections, définir (liste1) et définir (liste2)

>>> def common_elements(list1, list2):
...     return list(set(list1) & set(list2))
...
>>>
>>> common_elements([1,2,3,4,5,6], [3,5,7,9])
[3, 5]
>>>
>>> common_elements(['this','this','n','that'],['this','not','that','that'])
['this', 'that']
>>>
>>>

Notez que la liste de résultats peut être dans un ordre différent de la liste d'origine.

TU
la source
Merci pour l'aide. Comprenez où je me suis trompé et sur quoi travailler la prochaine fois. :)
Daniel
5
excellente solution. y a-t-il aussi un moyen de préserver l'ordre avec cela?
tarrasch
14

vous pouvez utiliser une simple compréhension de liste:

x=[1,2,3,4]
y=[3,4,5]
common = [i for i in x if i in y]
common: [3,4]
Mahdi Ghelichi
la source
9

Set est une autre façon de résoudre ce problème

a = [3,2,4]
b = [2,3,5]
set(a)&set(b)
{2, 3}
néo
la source
9

liste1 = [1,2,3,4,5,6] liste2 = [3,5,7,9]

Je sais que 3 façons peuvent résoudre ce problème, bien sûr, il pourrait y en avoir plus.

1-

common_elements = [e for e in list1 if e in list2]

2-

import numpy as np
common_elements = np.intersect1d(list1, list2)

3-

common_elements = set(list1).intersection(list2)

La troisième méthode est la plus rapide car les ensembles sont implémentés à l'aide de tables de hachage.

Mahmoud Reda
la source
8

Les réponses précédentes fonctionnent toutes pour trouver les éléments communs uniques, mais ne prendront pas en compte les éléments répétés dans les listes. Si vous souhaitez que les éléments communs apparaissent sous le même numéro qu'ils se trouvent en commun sur les listes, vous pouvez utiliser le one-liner suivant:

l2, common = l2[:], [ e for e in l1 if e in l2 and (l2.pop(l2.index(e)) or True)]

La or Truepièce n'est nécessaire que si vous vous attendez à ce que des éléments soient évalués False.

Dologan
la source
Solution
géniale
Cela devrait être la réponse qui aurait dû être choisie! Je suppose que cela fonctionne également pour les listes inégales. De plus, la plupart des solutions utilisent setce qui n'est pas stable (c'est-à-dire la commande est perdue).
lifebalance
7

J'ai comparé chacune des méthodes mentionnées par chaque réponse. En ce moment, j'utilise python 3.6.3 pour cette implémentation. C'est le code que j'ai utilisé:

import time
import random
from decimal import Decimal


def method1():
    common_elements = [x for x in li1_temp if x in li2_temp]
     print(len(common_elements))


def method2():
    common_elements = (x for x in li1_temp if x in li2_temp)
    print(len(list(common_elements)))


def method3():
    common_elements = set(li1_temp) & set(li2_temp)
    print(len(common_elements))


def method4():
    common_elements = set(li1_temp).intersection(li2_temp)
    print(len(common_elements))


if __name__ == "__main__":
    li1 = []
    li2 = []
    for i in range(100000):
        li1.append(random.randint(0, 10000))
        li2.append(random.randint(0, 10000))

    li1_temp = list(set(li1))
    li2_temp = list(set(li2))

    methods = [method1, method2, method3, method4]
    for m in methods:
        start = time.perf_counter()
        m()
        end = time.perf_counter()
        print(Decimal((end - start)))

Si vous exécutez ce code, vous pouvez voir que si vous utilisez la liste ou le générateur (si vous itérez sur le générateur, pas seulement l'utilisez. Je l'ai fait lorsque j'ai forcé le générateur à en afficher la longueur), vous obtenez presque les mêmes performances. Mais si vous utilisez set, vous obtenez de bien meilleures performances. De plus, si vous utilisez la méthode d'intersection, vous obtiendrez des performances un peu meilleures. le résultat de chaque méthode sur mon ordinateur est indiqué ci-dessous:

  1. méthode1: 0.8150673999999999974619413478649221360683441
  2. méthode2: 0.8329545000000001531148541289439890533685684
  3. méthode3: 0,0016547000000000089414697868051007390022277
  4. méthode4: 0,0010262999999999244948867271887138485908508
Sabre Solooki
la source
5

c'est ma proposition je pense que c'est plus facile avec des ensembles qu'avec une boucle for

def unique_common_items(list1, list2):
   # Produce the set of *unique* common items in two lists.
   return list(set(list1) & set(list2))
Elasri
la source
2

Pourquoi ne pas l'utiliser list comprehension?

Solution demi-ligne:

common_elements = [x for x in list1 if x in list2]
seralouk
la source
0

1) La méthode1 de sauvegarde de la liste1 est le dictionnaire, puis l'itération de chaque élément de la liste2

def findarrayhash(a,b):
    h1={k:1 for k in a}
    for val in b:
        if val in h1:
            print("common found",val)
            del h1[val]
        else:
            print("different found",val)
    for key in h1.iterkeys():
        print ("different found",key)

Trouver des éléments communs et différents:

2) Méthode 2 en utilisant set

def findarrayset(a,b):
    common = set(a)&set(b)
    diff=set(a)^set(b)
    print list(common)
    print list(diff) 
JS
la source
-1

Utilisez un générateur:

common = (x for x in list1 if x in list2)

L'avantage ici est que cela reviendra en temps constant (presque instantané) même lors de l'utilisation de listes énormes ou d'autres énormes itérables.

Par exemple,

list1 =  list(range(0,10000000))
list2=list(range(1000,20000000))
common = (x for x in list1 if x in list2)

Toutes les autres réponses ici prendront beaucoup de temps avec ces valeurs pour list1 et list2.

Vous pouvez ensuite itérer la réponse avec

for i in common: print(i)

Ou convertissez-le en liste avec

list(i)
cowlinator
la source
Cela ne produit pas de réponse. Le résultat est un générateur plutôt que la liste des éléments communs.
josiekre
1
Correct, cela crée un générateur, qui est une réponse. La question était d'obtenir en quelque sorte les éléments communs des 2 listes, ce que fait ce générateur. Parcourons simplement le générateur comme ceci: for i in common: print(i). Les générateurs sont des itérables qui sont fréquemment utilisés à la place d'autres itérables tels que les listes.
cowlinator