J'ai une liste de dictés et j'aimerais supprimer les dictionnaires avec des paires clé et valeur identiques.
Pour cette liste: [{'a': 123}, {'b': 123}, {'a': 123}]
Je voudrais rendre cela: [{'a': 123}, {'b': 123}]
Un autre exemple:
Pour cette liste: [{'a': 123, 'b': 1234}, {'a': 3222, 'b': 1234}, {'a': 123, 'b': 1234}]
Je voudrais rendre cela: [{'a': 123, 'b': 1234}, {'a': 3222, 'b': 1234}]
python
list
dictionary
Brenden
la source
la source
set()
Réponses:
Essaye ça:
La stratégie consiste à convertir la liste des dictionnaires en une liste de tuples où les tuples contiennent les éléments du dictionnaire. Puisque les tuples peuvent être hachés, vous pouvez supprimer les doublons en utilisant
set
(en utilisant une compréhension d'ensemble ici, une alternative plus ancienne à python seraitset(tuple(d.items()) for d in l)
) et, après cela, recréer les dictionnaires à partir de tuples avecdict
.où:
l
est la liste originaled
est l'un des dictionnaires de la listet
est l'un des tuples créés à partir d'un dictionnaireModifier: Si vous souhaitez conserver la commande, le one-liner ci-dessus ne fonctionnera pas car
set
ne le fera pas. Cependant, avec quelques lignes de code, vous pouvez également le faire:Exemple de sortie:
Remarque: comme indiqué par @alexis, il peut arriver que deux dictionnaires avec les mêmes clés et valeurs ne donnent pas le même tuple. Cela peut arriver s'ils passent par un autre historique d'ajout / suppression de clés. Si tel est le cas pour votre problème, envisagez de trier
d.items()
comme il le suggère.la source
d.items()
n'est pas garanti de renvoyer les éléments dans un ordre particulier. Vous devez fairetuple(sorted(d.items()))
pour vous assurer que vous n'obtenez pas différents tuples pour les mêmes paires clé-valeur.json
module comme je l'ai faitUn autre one-liner basé sur la compréhension de liste:
Ici comme on peut utiliser la
dict
comparaison, on ne garde que les éléments qui ne sont pas dans le reste de la liste initiale (cette notion n'est accessible que via l'indexn
, d'où l'utilisation deenumerate
).la source
if i not in d[n + 1:]
itère sur toute la liste des dictionnaires (à partir den
mais cela ne fait que diviser par deux le nombre total d'opérations) et vous effectuez cette vérification pour chaque élément de votre dictionnaire, donc ce code est une complexité temporelle O (n ^ 2)D'autres réponses ne fonctionneraient pas si vous utilisez des dictionnaires imbriqués tels que des objets JSON désérialisés. Pour ce cas, vous pouvez utiliser:
la source
Si l'utilisation d'un package tiers vous convient, vous pouvez utiliser
iteration_utilities.unique_everseen
:Il préserve l'ordre de la liste d'origine et ut peut également gérer les éléments non phasables comme les dictionnaires en recourant à un algorithme plus lent (
O(n*m)
oùn
sont les éléments de la liste d'origine etm
les éléments uniques de la liste d'origine au lieu deO(n)
). Dans le cas où les clés et les valeurs sont hachables, vous pouvez utiliser l'key
argument de cette fonction pour créer des éléments hachables pour le "test d'unicité" (afin qu'il fonctionneO(n)
).Dans le cas d'un dictionnaire (qui compare indépendamment de l'ordre), vous devez le mapper à une autre structure de données qui compare comme ça, par exemple
frozenset
:Notez que vous ne devez pas utiliser une
tuple
approche simple (sans tri) car les dictionnaires égaux n'ont pas nécessairement le même ordre (même en Python 3.7 où l' ordre d'insertion - et non l'ordre absolu - est garanti):Et même le tri du tuple peut ne pas fonctionner si les clés ne peuvent pas être triées:
Référence
J'ai pensé qu'il pourrait être utile de voir comment les performances de ces approches se comparent, alors j'ai fait un petit benchmark. Les graphiques de référence sont le temps par rapport à la taille de la liste sur la base d'une liste ne contenant aucun doublon (qui a été choisi arbitrairement, le temps d'exécution ne change pas de manière significative si j'ajoute certains ou beaucoup de doublons). C'est un tracé log-log donc la gamme complète est couverte.
Les temps absolus:
Les horaires relatifs à l'approche la plus rapide:
La deuxième approche de thefourtheye est la plus rapide ici. L'
unique_everseen
approche avec lakey
fonction est à la deuxième place, mais c'est l'approche la plus rapide qui préserve l'ordre. Les autres approches de jcollado et thefourtheye sont presque aussi rapides. L'approche utilisantunique_everseen
sans clé et les solutions d' Emmanuel et Scorpil sont très lentes pour les listes plus longues et se comportent bien plus malO(n*n)
au lieu deO(n)
. L' approche de stpk avecjson
n'est pas,O(n*n)
mais elle est beaucoup plus lente que lesO(n)
approches similaires .Le code pour reproduire les benchmarks:
Par souci d'exhaustivité, voici le timing d'une liste contenant uniquement des doublons:
Les horaires ne changent pas de manière significative, sauf
unique_everseen
sanskey
fonction, ce qui dans ce cas est la solution la plus rapide. Cependant, ce n'est que le meilleur cas (donc non représentatif) pour cette fonction avec des valeurs non phasables car son exécution dépend de la quantité de valeurs uniques dans la liste:O(n*m)
qui dans ce cas est juste 1 et donc elle s'exécuteO(n)
.Avertissement: je suis l'auteur de
iteration_utilities
.la source
Parfois, les boucles à l'ancienne sont toujours utiles. Ce code est un peu plus long que celui de jcollado, mais très facile à lire:
la source
0
entréerange(0, len(a))
n'est pas nécessaire.Si vous souhaitez conserver la commande, vous pouvez faire
Si l'ordre n'a pas d'importance, vous pouvez le faire
la source
dict_values
sortie non sérialisable au lieu d'une liste. Vous devez à nouveau lancer le tout dans une liste.list(frozen.....)
Si vous utilisez Pandas dans votre flux de travail, une option consiste à fournir une liste de dictionnaires directement au
pd.DataFrame
constructeur. Ensuite, utilisezdrop_duplicates
etto_dict
méthodes pour obtenir le résultat souhaité.la source
Ce n'est pas une réponse universelle , mais si votre liste est triée par une clé, comme ceci:
alors la solution est aussi simple que:
Résultat:
Fonctionne avec des dictionnaires imbriqués et préserve (évidemment) l'ordre.
la source
Vous pouvez utiliser un ensemble, mais vous devez transformer les dictionnaires en un type hachable.
Unique est maintenant égal
Pour récupérer les dicts:
la source
d.iteritems()
n'est pas garanti - vous pouvez donc vous retrouver avec des «doublons» dansunique
.Voici une solution rapide en une ligne avec une compréhension de liste doublement imbriquée (basée sur la solution de @Emmanuel).
Cela utilise une seule clé (par exemple,
a
) dans chaque dict comme clé primaire, plutôt que de vérifier si tout le dict correspondCe n'est pas ce que OP a demandé, mais c'est ce qui m'a amené à ce fil, alors j'ai pensé que je publierais la solution avec laquelle je me suis retrouvé
la source
Pas si court mais facile à lire:
Maintenant, la liste
list_of_data_uniq
aura des dictionnaires uniques.la source