0
votes

Soustraire une liste d'une autre en python où des valeurs en double peuvent se produire

Je cherche à supprimer le contenu d'un tableau d'un autre.

array_3 = [x for x in array_2 if x not in array_1]

Ma première pensée a été d'utiliser list compréhensions

array_2 = ['one' , "two" , "one", "three", "four"]
array_1 = ['one', "two"]

Cependant, cela supprimera l'élément en double résultat: ['three', 'four']

Je ne veux supprimer "one" qu'une seule fois du tableau car je recherche un soustraction de liste. Je veux donc que le résultat soit: ['un', 'trois', 'quatre'] .

Quelle est la bonne manière pythonique d'y parvenir?


5 commentaires

Double possible de Faire la différence entre deux listes


Non, les réponses fournies dans ce fil supprimeraient toutes les instances de 'one' Je souhaite uniquement supprimer une instance par instance, comme indiqué ci-dessus


Oui, ils le font. Une des réponses utilisant collections.Counter fait exactement cela, ce qui a déjà été répété plusieurs fois dans les réponses ci-dessous. La réponse: stackoverflow.com/questions/3462143/get-difference-between-t‌ Wo-lists / 42081195 # 42‌ 081195 .


excuses, cette réponse a été enfouie profondément parmi les harengs rouges


Est-ce que cela répond à votre question? Python supprimant le chevauchement des listes


5 Réponses :


3
votes

Essayez le Compteur à partir de collections :

['one', 'three', 'four']


1 commentaires

Celui-ci fonctionne probablement mieux que d'utiliser remove , car il ne nécessite qu'une seule boucle sur les deux listes. Pour les grandes listes, cela ferait une grande différence. Cependant, il ne maintient pas réellement l'ordre dans lequel tous les éléments de array_2 étaient.



1
votes

Vous pouvez utiliser la méthode remove de la liste:

array_2 = ['one' , "two" , "one", "three", "four"]
array_1 = ['one', "two"]

# copy list
array_3 = array_2[:]

for element in array_1:
    try:
        array_3.remove(element)
    except ValueError:
        pass
print(array_3)
# ['one', 'three', 'four']


2 commentaires

C'est en fait comme ça que j'ai résolu le problème. Pourquoi y aurait-il une erreur de mot clé 28 savez-vous?


Vous pouvez rechercher un ValueError au lieu d'un KeyError , car c'est ce qui est déclenché si la valeur n'est pas dans la liste.



0
votes

L'objet Counter est parfait pour cela.

In [7]: list((a2-a1).elements())                                                                                                                                             
Out[7]: ['one', 'three', 'four']

Si vous voulez une liste, vous pouvez aplatir le Counter en utilisant:

In [1]: from collections import Counter                                                                                                                                      

In [2]: array_2 = ['one' , "two" , "one", "three", "four"]                                                                                                                   

In [3]: array_1 = ['one', "two"]                                                                                                                                             

In [4]: a2 = Counter(array_2)                                                                                                                                                

In [5]: a1 = Counter(array_1)                                                                                                                                                

In [6]: a2 - a1                                                                                                                                                              
Out[6]: Counter({'one': 1, 'three': 1, 'four': 1})


0 commentaires

0
votes

L'utilisation de la fonction map en combinaison avec un lambda résoudrait votre tâche:

print(array_2)
# ['one', 'three', 'four']

Cela changerait le array_2 directement et le résultat serait:

map(lambda x: array_2.remove(x) if x in array_2 else None, array_1)


3 commentaires

@sentence Oui. Le résultat mentionné provient de la sortie du code exécuté.


Cela échouerait si array_1 contient un élément qui n'est pas présent dans array_2 .


@ 1313e Merci de l'avoir signalé. J'ai mis à jour le code pour en tenir compte.



0
votes

Je vais juste rassembler les excellentes solutions déjà données ci-dessus.

Si vous vous souciez de maintenir l'ordre d'origine dans lequel les éléments de array_2 étaient, alors je pense que vous devez utiliser remove :

from collections import Counter

array_1 = ['one', 'two']
array_2 = ['one', 'two', 'one', 'three', 'four']
array_3 = list((Counter(array_2) - Counter(array_1)).elements())
print(array_3)

Si l'ordre final des éléments n'a pas d'importance, alors utiliser Counter est beaucoup plus efficace car il ne boucle qu'une seule fois sur les deux listes:

array_1 = ['one', 'two']
array_2 = ['one', 'two', 'one', 'three', 'four']
array_3 = list(array_2)
for x in array_1:
    try:
        array_3.remove(x)
    except ValueError:
        pass
print(array_3)


3 commentaires

pour ce que cela vaut, j'ai trouvé que la réponse de @ Sparky05 s'est avérée être la plus rapide des deux sur mon ensemble de données


@Steve Oui, pour votre exemple, utiliser remove est plus rapide, car l'initialisation d'un objet Counter peut prendre un peu de temps. Cependant, si vous utilisiez deux listes qui ont des tailles supérieures, disons, 10k, alors utiliser Counter est beaucoup, beaucoup plus rapide.


@ 1313e Modifiez le code dans le premier bloc: array_3 = list (array_2) et pour x dans array_1: