web-dev-qa-db-fra.com

Supprimer tous les éléments présents dans une liste d'une autre

Disons que j'ai deux listes, l1 et l2. Je souhaite effectuer l1 - l2, qui renvoie tous les éléments de l1 et non dans l2.

Je peux penser à une approche de boucle naïve pour le faire, mais cela va être vraiment inefficace. Qu'est-ce qu'un moyen pythonique efficace de faire cela?

Par exemple, si j'ai l1 = [1,2,6,8] and l2 = [2,3,5,8], l1 - l2 devrait renvoyer [1,6]

284
fandom

Python a une fonctionnalité de langage appelée List Comprehensions qui est parfaitement adaptée pour rendre ce genre de choses extrêmement facile. L'instruction suivante fait exactement ce que vous voulez et stocke le résultat dans l3:

l3 = [x for x in l1 if x not in l2]

l3 contiendra [1, 6].

382
Donut

Une façon consiste à utiliser des ensembles:

>>> set([1,2,6,8]) - set([2,3,5,8])
set([1, 6])
117
Arkku

En développant la réponse de Donut et les autres réponses ici, vous pouvez obtenir des résultats encore meilleurs en utilisant une compréhension de générateur au lieu d'une compréhension de liste, et en utilisant une structure de données set (puisque l'opérateur in est O(n) sur une liste mais O(1) sur un ensemble).

Alors, voici une fonction qui fonctionnerait pour vous:

def filter_list(full_list, excludes):
    s = set(excludes)
    return (x for x in full_list if x not in s)

Le résultat sera un résultat itératif qui va chercher paresseusement la liste filtrée. Si vous avez besoin d’un objet de liste réel (par exemple, si vous devez créer une len() sur le résultat), vous pouvez facilement créer une liste comme ceci:

filtered_list = list(filter_list(full_list, excludes))
31
Daniel Pryden

Vous pouvez également utiliser filter avec l'expression lambda pour obtenir le résultat souhaité. Par exemple:

>>> l1 = [1,2,6,8]
>>> l2 = set([2,3,5,8])

#     v  `filter` returns the a iterator object. Here I'm type-casting 
#     v  it to `list` in order to display the resultant value
>>> list(filter(lambda x: x not in l2, l1))
[1, 6]

Comparaison des performances

Ici, je compare la performance de toutes les réponses mentionnées ici. Comme prévu, l'opération --- d'Arkkset est la plus rapide.

  • Différence de set d'Arkk - Premier [0.124 usec par boucle)

    mquadri$ python -m timeit -s "l1 = set([1,2,6,8]); l2 = set([2,3,5,8]);" "l1 - l2"
    10000000 loops, best of 3: 0.124 usec per loop
    
  • Compréhension de la liste de Daniel Pryden avec la recherche set - Deuxième [0,302 usec par boucle)

    mquadri$ python -m timeit -s "l1 = [1,2,6,8]; l2 = set([2,3,5,8]);" "[x for x in l1 if x not in l2]"
    1000000 loops, best of 3: 0.302 usec per loop
    
  • Compréhension de la liste de donuts sur la liste - Troisième [0.552 usec par boucle)

    mquadri$ python -m timeit -s "l1 = [1,2,6,8]; l2 = [2,3,5,8];" "[x for x in l1 if x not in l2]"
    1000000 loops, best of 3: 0.552 usec per loop
    
  • Moinuddin Quadri utilise filter - Quatrième [0.972 usec par boucle)

    mquadri$ python -m timeit -s "l1 = [1,2,6,8]; l2 = set([2,3,5,8]);" "filter(lambda x: x not in l2, l1)"
    1000000 loops, best of 3: 0.972 usec per loop
    
  • Akshay Hazari utilisant la combinaison de reduce + filter - Cinquième [3.97 usec par boucle)

    mquadri$ python -m timeit "l1 = [1,2,6,8]; l2 = [2,3,5,8];" "reduce(lambda x,y : filter(lambda z: z!=y,x) ,l1,l2)"
    100000 loops, best of 3: 3.97 usec per loop
    

PS: set ne conserve pas l'ordre et supprime les éléments en double de la liste. Par conséquent, n'utilisez pas set difference si vous en avez besoin.

29
Moinuddin Quadri

Utilisez le type de jeu Python. Ce serait le plus pythonique. :)

De plus, étant donné qu’elle est native, elle devrait également être la méthode la plus optimisée.

Voir:

http://docs.python.org/library/stdtypes.html#set

http://docs.python.org/library/sets.htm (pour les pythons plus anciens)

# Using Python 2.7 set literal format.
# Otherwise, use: l1 = set([1,2,6,8])
#
l1 = {1,2,6,8}
l2 = {2,3,5,8}
l3 = l1 - l2
28
nonot1

Solution alternative:

reduce(lambda x,y : filter(lambda z: z!=y,x) ,[2,3,5,8],[1,2,6,8])
7
Akshay Hazari