2009-08-14 7 views
4

rapide et très basique newbie question.supprimer les doublons de dictionnaires imbriqués dans la liste

Si j'ai liste des dictionnaires qui ressemble à ceci:

L = [] 
L.append({"value1": value1, "value2": value2, "value3": value3, "value4": value4}) 

Disons qu'il existe plusieurs entrées où value3 et valeur4 sont identiques à d'autres dictionnaires imbriqués. Comment puis-je trouver et supprimer rapidement et facilement ces dictionnaires en double.

L'ordre de conservation n'a pas d'importance.

Merci.

EDIT:

S'il y a cinq entrées, comme celui-ci:

L = [{"value1": fssd, "value2": dsfds, "value3": abcd, "value4": gk}, 
    {"value1": asdasd, "value2": asdas, "value3": dafdd, "value4": sdfsdf}, 
    {"value1": sdfsf, "value2": sdfsdf, "value3": abcd, "value4": gk}, 
    {"value1": asddas, "value2": asdsa, "value3": abcd, "value4": gk}, 
    {"value1": asdasd, "value2": dskksks, "value3": ldlsld, "value4": sdlsld}] 

La sortie shoud ressemble à ceci:

L = [{"value1": fssd, "value2": dsfds, "value3": abcd, "value4": gk}, 
    {"value1": asdasd, "value2": asdas, "value3": dafdd, "value4": sdfsdf}, 
    {"value1": asdasd, "value2": dskksks, "value3": ldlsld, "value4": sdlsld} 
+0

Pour clarifier, voulez-vous supprimer des paires clé/valeur s'il y a une paire clé/valeur dans un autre dictionnaire, ou si seulement la clé (pas nécessairement la valeur) existe dans un autre dictionnaire? – Triptych

+0

Est-ce juste les touches key3 et key4 qui ne peuvent pas être identiques? Que se passe-t-il si la valeur d'une clé correspond à la valeur d'une autre clé dans une autre dict? Soit dit en passant, nommez vos listes autrement que 'list', ou écrasez la' list' actuelle dans l'espace de noms intégré, et vous ne pourrez plus appeler la fonction 'list()' plus tard. 'lst' ou' list_' sont des alternatives assez courantes. –

+0

Oui, juste key3 et key4, le reste peut être dupliqué. –

Répondre

6

En Python 2.6 ou 3. *:

import itertools 
import pprint 

L = [{"value1": "fssd", "value2": "dsfds", "value3": "abcd", "value4": "gk"}, 
    {"value1": "asdasd", "value2": "asdas", "value3": "dafdd", "value4": "sdfsdf"}, 
    {"value1": "sdfsf", "value2": "sdfsdf", "value3": "abcd", "value4": "gk"}, 
    {"value1": "asddas", "value2": "asdsa", "value3": "abcd", "value4": "gk"}, 
    {"value1": "asdasd", "value2": "dskksks", "value3": "ldlsld", "value4": "sdlsld"}] 

getvals = operator.itemgetter('value3', 'value4') 

L.sort(key=getvals) 

result = [] 
for k, g in itertools.groupby(L, getvals): 
    result.append(g.next()) 

L[:] = result 
pprint.pprint(L) 

Presque même en Python 2.5, sauf que vous doit utiliser g.next() au lieu de next (g) dans l'append.

+0

Merci pour cette solution. –

1
for dic in list: 
    for anotherdic in list: 
    if dic != anotherdic: 
     if dic["value3"] == anotherdic["value3"] or dic["value4"] == anotherdic["value4"]: 
     list.remove(anotherdic) 

testé avec

list = [{"value1": 'fssd', "value2": 'dsfds', "value3": 'abcd', "value4": 'gk'}, 
{"value1": 'asdasd', "value2": 'asdas', "value3": 'dafdd', "value4": 'sdfsdf'}, 
{"value1": 'sdfsf', "value2": 'sdfsdf', "value3": 'abcd', "value4": 'gk'}, 
{"value1": 'asddas', "value2": 'asdsa', "value3": 'abcd', "value4": 'gk'}, 
{"value1": 'asdasd', "value2": 'dskksks', "value3": 'ldlsld', "value4": 'sdlsld'}] 

a bien fonctionné pour moi :)

1

C'est une liste d'un dictionnaire et mais, en supposant qu'il ya plus de dictionnaires dans la liste l:

l = [ldict for ldict in l if ldict.get("value3") != value3 or ldict.get("value4") != value4] 

Mais est-ce que vous voulez vraiment faire? Peut-être avez-vous besoin d'affiner votre description.

BTW, n'utilisez pas list comme nom car c'est le nom d'un built-in Python.

EDIT: En supposant que vous avez commencé avec une liste de dictionnaires, plutôt qu'une liste de listes de 1 dictionnaire chacune qui devrait fonctionner avec votre exemple. Il ne fonctionnera pas si l'une des valeurs avait pas, alors il vaut mieux quelque chose comme:

l = [ldict for ldict in l if not (("value3" in ldict and ldict["value3"] == value3) and ("value4" in ldict and ldict["value4"] == value4))] 

Mais il semble encore comme une structure de données hors du commun.

EDIT: inutile d'utiliser explicitement get s.

De plus, il y a toujours des compromis dans les solutions. Sans plus d'informations et sans réellement mesurer, il est difficile de savoir quels compromis de performance sont les plus importants pour le problème. Mais, comme le Zen sez: "Simple est mieux que complexe".

+0

Bonjour Ned, merci pour votre contribution, j'ai ajouté un exemple sur un INPUT et un OUTPUT de la même liste, aussi, j'ai renommé la liste, dans cet exemple précis. Merci. –

2

Vous pouvez utiliser une matrice temporaire pour stocker un élément. Le code précédent était buggé pour supprimer des éléments dans la boucle for.

(v,r) = ([],[]) 
for i in l: 
    if ('value4', i['value4']) not in v and ('value3', i['value3']) not in v: 
     r.append(i) 
    v.extend(i.items()) 
l = r 

Votre test:

l = [{"value1": 'fssd', "value2": 'dsfds', "value3": 'abcd', "value4": 'gk'}, 
    {"value1": 'asdasd', "value2": 'asdas', "value3": 'dafdd', "value4": 'sdfsdf'}, 
    {"value1": 'sdfsf', "value2": 'sdfsdf', "value3": 'abcd', "value4": 'gk'}, 
    {"value1": 'asddas', "value2": 'asdsa', "value3": 'abcd', "value4": 'gk'}, 
    {"value1": 'asdasd', "value2": 'dskksks', "value3": 'ldlsld', "value4": 'sdlsld'}] 

ouputs

{'value4': 'gk', 'value3': 'abcd', 'value2': 'dsfds', 'value1': 'fssd'} 
{'value4': 'sdfsdf', 'value3': 'dafdd', 'value2': 'asdas', 'value1': 'asdasd'} 
{'value4': 'sdlsld', 'value3': 'ldlsld', 'value2': 'dskksks', 'value1': 'asdasd'} 
+0

Votre sortie n'est pas correcte. Regarde mon exemple. Merci quand même pour la tentative. –

7

Voici une façon:

keyfunc = lambda d: (d['value3'], d['value4']) 

from itertools import groupby 
giter = groupby(sorted(L, key=keyfunc), keyfunc) 

L2 = [g[1].next() for g in giter] 
print L2 
+1

On dirait que le tien est correct et une heure plus tôt que celui d'Alex. – hughdbrown

+1

Je suppose qu'il est facile de manquer une fois qu'une question obtient plus de 5 ou 6 réponses. Probablement aide à être dans le premier * ou * dernier couple, je soupçonne. Pas de problème, mais merci d'avoir remarqué ça. :) – ars

+0

en cours d'exécution dans python3.3 et obtenir l'erreur 'AttributeError: 'itertools._grouper' objet n'a aucun attribut 'suivant' aucun indice? – lukik

0

Si je comprends bien, vous voulez jeter les matchs qui viennent plus tard la liste originale, mais ne se soucient pas de la o rder de la liste résultante, donc:

(testé avec 2.5.2)

tempDict = {} 
for d in L[::-1]: 
    tempDict[(d["value3"],d["value4"])] = d 
L[:] = tempDict.itervalues() 
tempDict = None 
+0

Avez-vous essayé d'exécuter votre code? Il ne fait pas ce que le PO demandait. Quelques questions: (1) Pourquoi parcourir la liste dans l'ordre inverse? (2) Pourquoi utiliser (d ["value3"], d ["value4"]) comme clé dans votre dictionnaire temporaire? (3) pourquoi assigner le dictionnaire courant dans la liste pendant l'itération comme valeur à votre dicitonary provisoire? – hughdbrown

+0

Hrm - fait ce que mon interprétation était (dont je n'étais pas sûr), et correspond également à sa sortie - mais pas l'ordre de celui-ci, mais il a dit que la préservation de ce n'était pas important. Mon interprétation: Lorsque plus d'un dictionnaire a la même paire (valeur3, valeur4), ne conserver que le premier dictionnaire de la liste originale. Et, la liste résultante de dicts ne doit pas être dans le même ordre. Alors ... (1) donc la première entrée dans la liste originale va "gagner" et être retenue, (2) parce que je pensais que c'était ce qui devait être unique, et (3) parce que les dictionnaires sont les valeurs que je retire pour le Nouvelle liste. – Anon

+0

(Dans ma sortie de test, les éléments dict s'exécutent dans l'ordre inverse, et la liste des dicts les a dans un ordre différent, mais puisqu'il a dit "Préserver l'ordre n'a aucune importance", cela semblait dans les paramètres.) – Anon

Questions connexes