Comment puis-je comparer deux listes en python et retourner des correspondances


381

Je veux prendre deux listes et trouver les valeurs qui apparaissent dans les deux.

a = [1, 2, 3, 4, 5]
b = [9, 8, 7, 6, 5]

returnMatches(a, b)

reviendrait [5], par exemple.


4
Les réponses ci-dessous me semblent toutes fausses. Que se passe-t-il si un nombre est répété dans l'une ou l'autre liste, vous voudrez sûrement savoir que (?) (Par exemple, disons que les deux listes ont '5' deux fois) Toute solution utilisant des ensembles supprimera immédiatement tous les éléments répétés et vous perdrez cette info.
MH

Réponses:


487

Ce n'est pas le plus efficace, mais de loin le moyen le plus évident de le faire est:

>>> a = [1, 2, 3, 4, 5]
>>> b = [9, 8, 7, 6, 5]
>>> set(a) & set(b)
{5}

si l'ordre est important, vous pouvez le faire avec des listes de compréhension comme celle-ci:

>>> [i for i, j in zip(a, b) if i == j]
[5]

(ne fonctionne que pour les listes de taille égale, ce qui implique une signification d'ordre).


15
Attention, la compréhension de la liste n'est pas forcément l'option la plus rapide. Pour les ensembles plus grands (où les performances sont les plus susceptibles d'avoir de l'importance), la comparaison au niveau du bit ( &) ou set(a).intersection(b)sera aussi rapide ou plus rapide que la compréhension de la liste.
Joshmaker

24
Une autre note de prudence: la compréhension de la liste trouve les valeurs qui apparaissent dans les deux aux mêmes positions (c'est ce que SilentGhost entendait par «l'ordre est significatif»). Les solutions d'intersection définies trouveront également des correspondances à DIFFÉRENTES positions. Ce sont des réponses à 2 questions très différentes ... (la question de l'op est ambigu quant à ce qu'il pose)
drevicko

Comment faites-vous cela si vos listes sont des listes de listes, c'est-à-dire a = [[0,0], [1,0]] et b = [[2,3], [0,0]]
Schneems

3
Quelle serait la complexité temporelle du premier exemple set(a) & set(b)?
AdjunctProfessorFalcon

Remarque, cela ne fonctionne pas si les deux ensembles sont vides et que vous vous attendez à ce que la comparaison réussisse. Alors changez en "(set (a) et set (b)) ou (not a and not b)"
Neil McGill

395

Utilisez set.intersection () , c'est rapide et lisible.

>>> set(a).intersection(b)
set([5])

28
Cette réponse a de bonnes performances algorithmiques, car une seule des listes (la plus courte devrait être préférée) est transformée en un ensemble pour une recherche rapide, et l'autre liste est parcourue en recherchant ses éléments dans l'ensemble.
u0b34a0f6ae

18
bool(set(a).intersection(b))pour TrueouFalse
Akshay

6
Cette réponse est plus flexible et plus lisible, car les gens peuvent avoir besoin de differenceou union.
Shihe Zhang

Que se passe-t-il si j'ai des objets en tant qu'éléments de liste et ne souhaite que des correspondances partielles, c'est-à-dire que seuls certains attributs doivent correspondre pour qu'il soit considéré comme un objet correspondant?
CGFoX

Existe-t-il une différence de performances pour .intersection()vs &?
brandonbanks

106

Un test de performance rapide montrant la solution de Lutz est le meilleur:

import time

def speed_test(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        for x in xrange(5000):
            results = func(*args, **kwargs)
        t2 = time.time()
        print '%s took %0.3f ms' % (func.func_name, (t2-t1)*1000.0)
        return results
    return wrapper

@speed_test
def compare_bitwise(x, y):
    set_x = frozenset(x)
    set_y = frozenset(y)
    return set_x & set_y

@speed_test
def compare_listcomp(x, y):
    return [i for i, j in zip(x, y) if i == j]

@speed_test
def compare_intersect(x, y):
    return frozenset(x).intersection(y)

# Comparing short lists
a = [1, 2, 3, 4, 5]
b = [9, 8, 7, 6, 5]
compare_bitwise(a, b)
compare_listcomp(a, b)
compare_intersect(a, b)

# Comparing longer lists
import random
a = random.sample(xrange(100000), 10000)
b = random.sample(xrange(100000), 10000)
compare_bitwise(a, b)
compare_listcomp(a, b)
compare_intersect(a, b)

Voici les résultats sur ma machine:

# Short list:
compare_bitwise took 10.145 ms
compare_listcomp took 11.157 ms
compare_intersect took 7.461 ms

# Long list:
compare_bitwise took 11203.709 ms
compare_listcomp took 17361.736 ms
compare_intersect took 6833.768 ms

Évidemment, tout test de performance artificiel doit être effectué avec un grain de sel, mais comme la set().intersection()réponse est au moins aussi rapide que les autres solutions, et aussi la plus lisible, elle devrait être la solution standard pour ce problème commun.


Set supprime les répétitions, donc dans mon cas, ne fonctionnera pas
rgralma

@rgralma créer un nouveau à setpartir d'un existant listne supprimera rien de l'original list. Si vous voulez une logique spéciale pour gérer les doublons dans une liste, je pense que vous devrez poser une nouvelle question car la réponse devra être spécifique à la façon dont vous voulez que les doublons soient traités.
Joshmaker


15

La façon la plus simple de le faire est d'utiliser des ensembles :

>>> a = [1, 2, 3, 4, 5]
>>> b = [9, 8, 7, 6, 5]
>>> set(a) & set(b)
set([5])


14
>>> s = ['a','b','c']   
>>> f = ['a','b','d','c']  
>>> ss= set(s)  
>>> fs =set(f)  
>>> print ss.intersection(fs)   
   **set(['a', 'c', 'b'])**  
>>> print ss.union(fs)        
   **set(['a', 'c', 'b', 'd'])**  
>>> print ss.union(fs)  - ss.intersection(fs)   
   **set(['d'])**

1
La réponse acceptée ne fonctionne pas pour les listes contenant des chaînes. Celui-ci le fait.
Antony

12

Vous pouvez également essayer ceci, en gardant les éléments communs dans une nouvelle liste.

new_list = []
for element in a:
    if element in b:
        new_list.append(element)

5

Voulez-vous des doublons? Sinon, vous devriez plutôt utiliser des ensembles:


>>> set([1, 2, 3, 4, 5]).intersection(set([9, 8, 7, 6, 5]))
set([5])

Si vous voulez vraiment des listes, java2s.com/Code/Python/List/Functiontointersecttwolists.htm >>> intersect ([1, 2, 3, 4, 5], [9, 8, 7, 6, 5]) [5 ]
Timothy Pratley

Selon le doc - ... exclut les constructions sujettes aux erreurs comme Set ('abc') & 'cbs' en faveur de Set plus lisible ('abc'). Intersection ('cbs'). - docs.python.org/library/sets.html
Aaron Newton

5

une autre façon un peu plus fonctionnelle de vérifier l'égalité des listes pour la liste 1 (lst1) et la liste 2 (lst2) où les objets ont une profondeur un et qui maintient l'ordre est:

all(i == j for i, j in zip(lst1, lst2))   

4
a = [1, 2, 3, 4, 5]
b = [9, 8, 7, 6, 5]

lista =set(a)
listb =set(b)   
print listb.intersection(lista)   
returnMatches = set(['5']) #output 

print " ".join(str(return) for return in returnMatches ) # remove the set()   

 5        #final output 

1
Bien que ce code puisse répondre à la question, fournir un contexte supplémentaire concernant la manière et / ou la raison pour laquelle il résout le problème améliorerait la valeur à long terme de la réponse.
Donald Duck

4

Peut également utiliser itertools.product.

>>> common_elements=[]
>>> for i in list(itertools.product(a,b)):
...     if i[0] == i[1]:
...         common_elements.append(i[0])

3

Vous pouvez utiliser

def returnMatches(a,b):
       return list(set(a) & set(b))

3

Vous pouvez utiliser:

a = [1, 3, 4, 5, 9, 6, 7, 8]
b = [1, 7, 0, 9]
same_values = set(a) & set(b)
print same_values

Production:

set([1, 7, 9])

4
en quoi est-ce différent de la réponse acceptée d'il y a 6 ans et plus?
tmdavison

1
Eh bien, j'ai écrit le détail complet avec une sortie et bon pour le python débutant
Adnan Ghaffar

2

Si vous voulez une valeur booléenne:

>>> a = [1, 2, 3, 4, 5]
>>> b = [9, 8, 7, 6, 5]
>>> set(b) == set(a)  & set(b) and set(a) == set(a) & set(b)
False
>>> a = [3,1,2]
>>> b = [1,2,3]
>>> set(b) == set(a)  & set(b) and set(a) == set(a) & set(b)
True

1

La solution suivante fonctionne pour n'importe quel ordre des éléments de liste et prend également en charge les deux listes pour être de longueur différente.

import numpy as np
def getMatches(a, b):
    matches = []
    unique_a = np.unique(a)
    unique_b = np.unique(b)
    for a in unique_a:
        for b in unique_b:
            if a == b:
                matches.append(a)
    return matches
print(getMatches([1, 2, 3, 4, 5], [9, 8, 7, 6, 5, 9])) # displays [5]
print(getMatches([1, 2, 3], [3, 4, 5, 1])) # displays [1, 3]

1
Numpy a une fonction spécifique pour cela:np.intersect1d(list1, list2)
obchardon

0

L'utilisation de la __and__méthode d'attribut fonctionne également.

>>> a = [1, 2, 3, 4, 5]
>>> b = [9, 8, 7, 6, 5]
>>> set(a).__and__(set(b))
set([5])

ou simplement

>>> set([1, 2, 3, 4, 5]).__and__(set([9, 8, 7, 6, 5]))
set([5])
>>>    

0
you can | for set union and & for set intersection.
for example:

    set1={1,2,3}
    set2={3,4,5}
    print(set1&set2)
    output=3

    set1={1,2,3}
    set2={3,4,5}
    print(set1|set2)
    output=1,2,3,4,5

curly braces in the answer.

4
La question était pour la liste et aucun ensemble. l'utilisation de l' &opérateur sur le plateau est déjà répondu par SilentGhost dans la réponse acceptée
dWinder

0

Je viens d'utiliser les éléments suivants et cela a fonctionné pour moi:

group1 = [1, 2, 3, 4, 5]
group2 = [9, 8, 7, 6, 5]

for k in group1:
    for v in group2:
        if k == v:
            print(k)

cela afficherait alors 5 dans votre cas. Probablement pas de bonnes performances.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.