2012-01-05 23 views
17

Ho la seguente Python 2.7 dizionario struttura dati (non controllo dati di origine - proviene da un altro sistema come è):Rimozione duplicati da dizionario

 
{112762853378: 
    {'dst': ['10.121.4.136'], 
    'src': ['1.2.3.4'], 
    'alias': ['www.example.com'] 
    }, 
112762853385: 
    {'dst': ['10.121.4.136'], 
    'src': ['1.2.3.4'], 
    'alias': ['www.example.com'] 
    }, 
112760496444: 
    {'dst': ['10.121.4.136'], 
    'src': ['1.2.3.4'] 
    }, 
112760496502: 
    {'dst': ['10.122.195.34'], 
    'src': ['4.3.2.1'] 
    }, 
112765083670: ... 
} 

Le chiavi del dizionario sarà sempre unico. Dst, src e alias possono essere duplicati. Tutti i record avranno sempre un dst e un src ma non tutti i record avranno necessariamente un alias visto nel terzo record.

Nei dati di esempio, uno dei primi due record sarebbe stato rimosso (non mi importa quale). Il terzo record sarebbe considerato univoco in quanto, sebbene dst e src siano gli stessi, manca l'alias.

Il mio obiettivo è rimuovere tutti i record in cui dst, src e alias sono stati tutti duplicati, indipendentemente dalla chiave.

In che modo questo rookie esegue questo?

Inoltre, la mia comprensione limitata di Python interpreta la struttura dati come un dizionario con i valori memorizzati nei dizionari ... un dotto di dicts, è corretto?

risposta

26

si potrebbe andare anche se ognuno degli elementi (la coppia chiave-valore) nel dizionario e aggiungerli in un dizionario risultato se il valore era non già nel dizionario dei risultati.

input_raw = {112762853378: 
    {'dst': ['10.121.4.136'], 
    'src': ['1.2.3.4'], 
    'alias': ['www.example.com'] 
    }, 
112762853385: 
    {'dst': ['10.121.4.136'], 
    'src': ['1.2.3.4'], 
    'alias': ['www.example.com'] 
    }, 
112760496444: 
    {'dst': ['10.121.4.136'], 
    'src': ['1.2.3.4'] 
    }, 
112760496502: 
    {'dst': ['10.122.195.34'], 
    'src': ['4.3.2.1'] 
    } 
} 

result = {} 

for key,value in input_raw.items(): 
    if value not in result.values(): 
     result[key] = value 

print result 
+4

Questo è un buon punto di partenza, ma mi sento in dovere di sottolineare che sarà lento per grandi raccolte di dati, perché con ogni ciclo, crea un nuovo elenco di valori e fa una ricerca lineare su di esso. – senderle

+0

Questo ha funzionato con semplicità e bellezza. –

+0

@ senderle: Apprezzo il tuo pensiero e commento riguardo la velocità e prenderò in considerazione se necessario. Ti interessa ampliare questa risposta per aumentare le prestazioni? –

2

Un approccio semplice sarebbe quello di creare un dizionario inverso utilizzando la concatenazione dei dati di stringa in ciascun dizionario interno come chiave. Quindi dire che hai i dati di cui sopra in un dizionario, d:

>>> import collections 
>>> reverse_d = collections.defaultdict(list) 
>>> for key, inner_d in d.iteritems(): 
...  key_str = ''.join(inner_d[k][0] for k in ['dst', 'src', 'alias'] if k in inner_d) 
...  reverse_d[key_str].append(key) 
... 
>>> duplicates = [keys for key_str, keys in reverse_d.iteritems() if len(keys) > 1] 
>>> duplicates 
[[112762853385, 112762853378]] 

Se non si desidera un elenco di duplicati o qualcosa di simile, ma vuole solo creare un duplicato dict-less, si potrebbe utilizzare un normale dizionario invece di un defaultdict e ri-invertire in questo modo:

>>> for key, inner_d in d.iteritems(): 
...  key_str = ''.join(inner_d[k][0] for k in ['dst', 'src', 'alias'] if k in inner_d) 
...  reverse_d[key_str] = key 
>>> new_d = dict((val, d[val]) for val in reverse_d.itervalues()) 
+0

Molto complicato! – eyquem

1

Dal momento che il modo per trovare l'unicità di corrispondenze è esattamente di usare un dizionario, con il valore unico desiderato essere la chiave, la strada da percorrere è quello di creare un dict invertito, dove i valori sono composti come la chiave - quindi ricreare un dizionario "de-reverse" usando il risultato intermedio.

dct = {112762853378: 
    {'dst': ['10.121.4.136'], 
    'src': ['1.2.3.4'], 
    'alias': ['www.example.com'] 
    }, 
112762853385: 
    {'dst': ['10.121.4.136'], 
    'src': ['1.2.3.4'], 
    'alias': ['www.example.com'] 
    }, 
112760496444: 
    {'dst': ['10.121.4.136'], 
    'src': ['1.2.3.4'] 
    }, 
112760496502: 
    {'dst': ['10.122.195.34'], 
    'src': ['4.3.2.1'] 
    }, 
    } 

def remove_dups (dct): 
    reversed_dct = {} 
    for key, val in dct.items(): 
     new_key = tuple(val["dst"]) + tuple(val["src"]) + (tuple(val["alias"]) if "alias" in val else (None,)) 
     reversed_dct[new_key] = key 
    result_dct = {} 
    for key, val in reversed_dct.items(): 
     result_dct[val] = dct[val] 
    return result_dct 

result = remove_dups(dct) 
+0

Molto complicato – eyquem

0
from collections import defaultdict 

dups = defaultdict(lambda : defaultdict(list)) 

for key, entry in data.iteritems(): 
    dups[tuple(entry.keys())][tuple([v[0] for v in entry.values()])].append(key) 

for dup_indexes in dups.values(): 
    for keys in dup_indexes.values(): 
     for key in keys[1:]: 
      if key in data: 
       del data[key] 
+0

Overcomplicated – eyquem

1
dups={} 

for key,val in dct.iteritems(): 
    if val.get('alias') != None: 
     ref = "%s%s%s" % (val['dst'] , val['src'] ,val['alias'])# a simple hash 
     dups.setdefault(ref,[]) 
     dups[ref].append(key) 

for k,v in dups.iteritems(): 
    if len(v) > 1: 
     for key in v: 
      del dct[key] 
+0

Ha dovuto aggiornare questo. Dovrebbe funzionare ora, se ho capito bene la domanda. – joel3000

2

Un'altra variazione dict inverso:

>>> import pprint 
>>> 
>>> data = { 
... 112762853378: 
... {'dst': ['10.121.4.136'], 
...  'src': ['1.2.3.4'], 
...  'alias': ['www.example.com'] 
... }, 
... 112762853385: 
... {'dst': ['10.121.4.136'], 
...  'src': ['1.2.3.4'], 
...  'alias': ['www.example.com'] 
... }, 
... 112760496444: 
... {'dst': ['10.121.4.136'], 
...  'src': ['1.2.3.4'] 
... }, 
... 112760496502: 
... {'dst': ['10.122.195.34'], 
...  'src': ['4.3.2.1'] 
... }, 
... } 
>>> 
>>> keep = set({repr(sorted(value.items())):key 
...    for key,value in data.iteritems()}.values()) 
>>> 
>>> for key in data.keys(): 
...  if key not in keep: 
...   del data[key] 
... 
>>> 
>>> pprint.pprint(data) 
{112760496444L: {'dst': ['10.121.4.136'], 'src': ['1.2.3.4']}, 
112760496502L: {'dst': ['10.122.195.34'], 'src': ['4.3.2.1']}, 
112762853378L: {'alias': ['www.example.com'], 
       'dst': ['10.121.4.136'], 
       'src': ['1.2.3.4']}} 
+0

Bello ma complicato secondo me – eyquem

+0

Sembra che questo conterebbe '{'src': ['1.2.3.4'], 'dst': ['10.121.3.1236']}' e '{'src': ['10.121 .3.1236 '],' dst ': [' 1.2.3.4 ']} 'come duplicati l'uno dell'altro ... – senderle

+0

@senderle. Ben individuato! Risolto il problema ora, FWIW. Probabilmente dovrei anche sottolineare che questa soluzione, sebbene compatta, è piuttosto inefficiente rispetto ad altre. – ekhumoro

2
input_raw = {112762853378: {'dst': ['10.121.4.136'], 
          'src': ['1.2.3.4'], 
          'alias': ['www.example.com'] }, 
      112762853385: {'dst': ['10.121.4.136'], 
          'src': ['1.2.3.4'], 
          'alias': ['www.example.com'] }, 
      112760496444: {'dst': ['10.121.4.299'], 
          'src': ['1.2.3.4'] }, 
      112760496502: {'dst': ['10.122.195.34'], 
          'src': ['4.3.2.1'] }, 
      112758601487: {'src': ['1.2.3.4'], 
          'alias': ['www.example.com'], 
          'dst': ['10.121.4.136']}, 
      112757412898: {'dst': ['10.122.195.34'], 
          'src': ['4.3.2.1'] }, 
      112757354733: {'dst': ['124.12.13.14'], 
          'src': ['8.5.6.0']},    
      } 

for x in input_raw.iteritems(): 
    print x 
print '\n---------------------------\n' 

seen = [] 

for k,val in input_raw.items(): 
    if val in seen: 
     del input_raw[k] 
    else: 
     seen.append(val) 


for x in input_raw.iteritems(): 
    print x 

risultato

(112762853385L, {'src': ['1.2.3.4'], 'dst': ['10.121.4.136'], 'alias': ['www.example.com']}) 
(112757354733L, {'src': ['8.5.6.0'], 'dst': ['124.12.13.14']}) 
(112758601487L, {'src': ['1.2.3.4'], 'dst': ['10.121.4.136'], 'alias': ['www.example.com']}) 
(112757412898L, {'src': ['4.3.2.1'], 'dst': ['10.122.195.34']}) 
(112760496502L, {'src': ['4.3.2.1'], 'dst': ['10.122.195.34']}) 
(112760496444L, {'src': ['1.2.3.4'], 'dst': ['10.121.4.299']}) 
(112762853378L, {'src': ['1.2.3.4'], 'dst': ['10.121.4.136'], 'alias': ['www.example.com']}) 

--------------------------- 

(112762853385L, {'src': ['1.2.3.4'], 'dst': ['10.121.4.136'], 'alias': ['www.example.com']}) 
(112757354733L, {'src': ['8.5.6.0'], 'dst': ['124.12.13.14']}) 
(112757412898L, {'src': ['4.3.2.1'], 'dst': ['10.122.195.34']}) 
(112760496444L, {'src': ['1.2.3.4'], 'dst': ['10.121.4.299']}) 

I fatti che questa soluzione crea prima un elenco input_raw.iteritems() (come nella risposta di Andrew's Cox) e richiede una lista crescente visto sono svantaggi.
Ma il primo non può essere evitato (usando iteritems() non funziona) e il secondo è meno pesante di ricreare un elenco result.values ​​() dalla lista crescente risultato per ogni turno di un ciclo continuo.

-2
example = { 
    'id1': {'name': 'jay','age':22,}, 
    'id2': {'name': 'salman','age': 52,}, 
    'id3': {'name':'Ranveer','age' :26,}, 
    'id4': {'name': 'jay', 'age': 22,}, 
} 
for item in example: 
    for value in example: 
     if example[item] ==example[value]: 
      if item != value: 
       key = value 
       del example[key] 
print "example",example   
+0

Si prega di formattare la risposta con il pulsante '{}', la formattazione è importante in Python. Ed è una pessima idea modificare liste o dizionari, mentre si sta ripetendo su di essi. Molto brutto. – MrT

+0

Benvenuto in StackOverflow: se inserisci codice, XML o campioni di dati, evidenzia queste righe nell'editor di testo e fai clic sul pulsante "esempi di codice" ({}) sulla barra degli strumenti dell'editor o su Ctrl + K sulla tastiera per il formato e la sintassi lo evidenziano! – WhatsThePoint

Problemi correlati