2012-01-05 34 views
17

Mam następującą strukturę Python 2.7 słownika danych (ja nie kontrolują dane źródłowe - pochodzi z innego systemu, jak jest):usuwanie duplikatów ze słownika

 
{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: ... 
} 

Do słownika klucze zawsze będzie wyjątkowy. Dst, src i alias mogą być duplikatami. Wszystkie rekordy będą zawsze miały dst i src, ale nie każdy rekord będzie musiał mieć alias widziany w trzecim rekordzie.

W przykładowych danych usunięty zostanie jeden z dwóch pierwszych rekordów (nie ma znaczenia, który z nich). Trzeci rekord będzie uważany za wyjątkowy, ponieważ chociaż dst i src są takie same, to brakuje im aliasu.

Moim celem jest usunięcie wszystkich rekordów, w których dst, src i alias zostały zduplikowane - niezależnie od klucza.

W jaki sposób ten debiutant osiągnąć?

Ponadto, moje ograniczone rozumienie Pythona interpretuje strukturę danych jako słownik z wartościami przechowywanymi w słownikach ... dyktowaniem dykt, czy to prawda?

Odpowiedz

26

można pójść chociaż każdy z elementów (pary klucz wartość) w słowniku i dodać je do słownika odczytu, jeśli wartość była nie jest już w słowniku wyników.

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

To dobry punkt wyjścia, ale czuję się zmuszony wskazać, że będzie on powolny dla dużych zbiorów danych, ponieważ z każdą pętlą tworzy nową listę wartości i wykonuje liniowe przeszukiwanie nad nią. – senderle

+0

To działało z prostotą i pięknem. –

+0

@senderle: Doceniam twoją myśl i komentarz dotyczący prędkości i w razie potrzeby uwzględniam ją. Czy chcesz rozszerzyć tę odpowiedź, aby zwiększyć wydajność? –

2

Jednym prostym podejściem byłoby stworzenie odwrotnego słownika z użyciem konkatenacji danych ciągu w każdym wewnętrznym słowniku jako klucza. Więc mówisz, że mają powyższe dane w słowniku, 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]] 

Jeśli nie chcesz listę duplikatów lub coś podobnego, ale po prostu chcesz utworzyć duplikat mniej dict, można po prostu użyć regularne słownika zamiast defaultdict i ponownie odwrócić go tak:

>>> 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

Tyle skomplikowane! – eyquem

1

Ponieważ sposobem na znalezienie wyjątkowość w korespondencji jest dokładnie używać słownika, z pożądaną wyjątkowa wartość jest kluczem, do zrobienia jest stworzenie odwróconą dict, gdzie wartości są zbudowane jako klucz - następnie odtwórz słownik "odwrócony" używając wyniku pośredniego.

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

Tyle skomplikowane – 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

Skomplikowane – 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

Musiałem to zaktualizować. Powinien teraz działać, jeśli dobrze rozumiem pytanie. – joel3000

2

Inną odmianą DICT odwrotnie:

>>> 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

Dobra, ale skomplikowana moim zdaniem – eyquem

+0

Wygląda na to, że będzie się liczyć '{'src': ['1.2.3.4'], 'dst': ['10.121.3.1236']}' and '{'src': ['10.121 .3.1236 '],' dst ': [' 1.2.3.4 ']} 'jako duplikaty siebie ... – senderle

+0

@ senderle. Dobrze zauważony! Naprawiono to teraz, FWIW. Powinienem też chyba zaznaczyć, że to rozwiązanie, mimo że kompaktowe, jest dość nieefektywne w porównaniu do niektórych innych. – 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 

wynik

(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']}) 

Fakt, że to rozwiązanie Crea Najpierw lista input_raw.iteritems() (jak w odpowiedzi Andrew Coxa) i wymaga rosnącej listy postrzegana są wady.
Ale pierwsze nie da się uniknąć (używając iteritems() nie działa), a drugi jest mniej ciężka niż ponowne tworzenie listy result.values ​​() z rosnącej listy wynik dla każdego przełomie pętla.

-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

Proszę sformatować odpowiedź za pomocą przycisku '{}, format ma znaczenie w języku Python. I jest to bardzo zły pomysł, aby modyfikować listy lub słowniki, a jednocześnie iterować nad nimi. Bardzo źle. – MrT

+0

Witamy w StackOverflow: jeśli publikujesz kod, XML lub próbki danych, zaznacz te linie w edytorze tekstu i kliknij przycisk "próbki kodu" ({}) na pasku narzędzi edytora lub użyj Ctrl + K na klawiaturze, aby ładnie format i składnia to podkreślają! – WhatsThePoint

Powiązane problemy