11
votes

Comment supprimer des éléments en double d'une liste à l'aide de la compréhension de la liste?

Comment supprimer des éléments en double d'une liste à l'aide de la compréhension de la liste? J'ai suivi du code suivant: xxx

mais cela ne fonctionne pas, produit uniquement une liste identique. Pourquoi sa production d'une liste identique?


4 commentaires

Parce que B est vide pour le moment où vous exécutez si l'élément n'est pas dans B . La compréhension de la liste est effectuée en mémoire et le résultat est attribué à B à la fin.


Cela signifie que la compréhension de la liste ne fonctionne pas comme une boucle?


Si vous ne voulez pas utiliser un ensemble, car vous souhaitez conserver la commande, consultez le unique_everseen itérateur dans le ITERTOOLS Recettes . Utilisez comme ceci: b = liste (unique_everseen (a))


C'est une sorte de boucle, mais cela génère le résultat en une fois ... ce n'est pas si surprenant non plus. Chaque fois que vous avez l'expression x = y , alors y est évalué d'abord, puis le résultat est attribué à x . Mais pendant l'évaluation de y , x n'est pas modifié. Auriez-vous eu les mêmes doutes si vous aviez B = liste (élément pour l'élément dans un élément IF non in b) à la place?


8 Réponses :


12
votes

Si cela ne vous dérange pas d'utiliser une technique différente de la compréhension de la liste, vous pouvez utiliser un ensemble pour cela:

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


3 commentaires

J'ai examiné la fonction définie, je veux simplement savoir ce qui ne va pas avec le code ci-dessus et si cela pourrait être corrigé?


ensemble ne gardera pas la commande initiale ... alors prenez notification de cela


@AdrioBan: que peut être corrigé avec des modifications de code minimes . Il est plus lent que d'utiliser Set , mais pas beaucoup plus lent si vous êtes sur 3,6+ (si vous êtes sur 3,5 et plus tôt en utilisant ordonnancierddict , C'est un succès plus grand;> 3x Runtime, tandis que 3,6+ avec un clair dict est seulement environ une augmentation de 66% du temps d'exécution).



5
votes

Utilisez clés code> sur un dict code> construit avec des valeurs dans A code> comme clé.

b = [i for i in set(a)]


0 commentaires

13
votes

Il produit une liste identique comme B code> ne contient aucun élément au moment de l'exécution. Ce que vous voudriez cela:

>>> a = [1, 2, 3, 3, 5, 9, 6, 2, 8, 5, 2, 3, 5, 7, 3, 5, 8]
>>> b = []
>>> [b.append(item) for item in a if item not in b]
[None, None, None, None, None, None, None, None]
>>> b
[1, 2, 3, 5, 9, 6, 8, 7]


2 commentaires

Méfiez-vous d'utiliser compréhensions de liste pour les effets secondaires . Utilisez une boucle régulière à la place.


C'est aussi un O (n²) réponse, où, pour les entrées hachables, o (n) est possible ( avec ou sans Préservation de la commande), et pour les entrées sans-frère, mais des entrées tricables, O (n journal n) est possible (bien qu'il remplace la commande originale avec la commande triée, à moins que vous n'auriez pas accompli à décorer et d'indéterminer les entrées avec leur index et de l'intégrer dans le tri et la déduplication donc une seconde Trier peut restaurer la commande originale).



4
votes

La raison pour laquelle la liste est inchangée est que B commence vide. Cela signifie que si l'élément non in b est toujours vrai . Ce n'est qu'après que la liste a été générée est cette nouvelle liste non vide attribuée à la variable B .


2 commentaires

Si je comprends bien, cela signifie que la compréhension de la liste ajoute des éléments à une option au lieu de vérifier et d'ajouter chaque élément à une heure comme en boucle.


@ALINWNDRLD: Je ne pense pas que ce soit une conclusion valable. Cela signifie seulement que la compréhension de la liste est évaluée avant l'affectation. La liste peut bien être construite dans une boucle en interne.



4
votes

Utilisez Groupby :

>>> {k: len(list(v)) for k, v in groupby(sorted(a))}
{1: 1, 2: 3, 3: 4, 5: 4, 6: 1, 7: 1, 8: 2, 9: 1}


0 commentaires

0
votes
>>> a = [10,20,30,20,10,50,60,40,80,50,40,0,100,30,60]
>>> [a.pop(a.index(i, a.index(i)+1)) for i in a if a.count(i) > 1]
>>> print(a)

0 commentaires

1
votes
>>> from itertools import groupby
>>> repeated_items = [2,2,2,2,3,3,3,3,4,5,1,1,1]
>>> [
...     next(group)
...     for _, group in groupby(
...         repeated_items,
...         key=repeated_items.index
...     )
... ]
[2, 3, 4, 5, 1]

1 commentaires

Solution intelligente, j'aime bien. Inconvénient est l'appel index , ce qui le fait O (n²) et l'hypothèse que l'entrée est déjà regroupée (elle ne fonctionnera pas sur [2, [2, 1,2] ). Vous pouvez résoudre les deux problèmes, et préserver toujours l'ordre de saisie, avec une transformation Schwartzian modifiée (nécessite à partir d'iTerTools Importer comptage, groupeby ): [v pour v, _ Dans Trié ([Suivant (GRP) pour _, GRP en Groupby (trié (zip (répété (répétid_items, comptage ())), clé = lambda x: x [0])], touche = lambda x: x [1])] . Pourrait ne pas valoir la peine, mais j'aime un bon bit de iTertools Insanity alimenté.



1
votes

Pour Python 3.6+, il y a une amélioration à avoir eu une amélioration de Niek de Klein's surtout excellente solution (c'est une faille principale être qu'il perd une commande de saisie). Étant donné que dict code> s sont maintenant insertions-ordonnés, vous pouvez simplement faire: xxx pré>

sur Python antérieur, vous feriez: p>

from collections import OrderedDict

b = list(OrderedDict.fromkeys(a))


0 commentaires