2009-07-31 13 views
5

Ok, utknąłem, potrzebuje pomocy od tej chwili ...Filtrowanie słowników i tworzenie słowników podrzędnych na podstawie kluczy/wartości w języku Python?

Jeśli mam głównego słownika takiego:

data = [ {"key1": "value1", "key2": "value2", "key1": "value3"}, 
{"key1": "value4", "key2": "value5", "key1": "value6"}, 
{"key1": "value1", "key2": "value8", "key1": "value9"} ] 

Teraz muszę przejść przez ten już słowniku formatować niektóre dane, tj:

for datadict in data: 
    for key, value in datadict.items(): 
    ...filter the data... 

teraz, jak bym w tej samej pętli jakoś (jeśli to możliwe ... jeśli nie, proszę sugerować alternatywy) sprawdzić dla wartości niektórych klawiszy, a jeśli te wartości Dopasuj moje ustawienia, a następnie dodaję całą listę do innego słownika, a więc sku-tecznie tworzenie mniejszych słowników, gdy przechodzę z tego głównego słownika na podstawie pewnych kluczy i wartości?

Więc powiedzmy, że chcemy utworzyć sub-słownik z wszystkich list, w którym klucz1 ma wartość „wartość1”, który na powyższej liście dałaby mi coś takiego:

subdata = [ {"key1": "value1", "key2": "value2", "key1": "value3"}, 
{"key1": "value1", "key2": "value8", "key1": "value9"} ] 
+1

"Główny słownik taki jak ten" nie jest poprawny. Masz listę słowników. –

+0

A klucze słownika są unikalne, więc nie można skonstruować słownika z duplikatami takich kluczy: {"klucz1": "wartość1", "klucz2": "wartość2", "klucz1": "wartość3"}; wynikiem jest {'key2': 'value2', 'key1': 'value3'}. Jeśli naprawdę chcesz duplikaty, potrzebujesz listy, więc ogólna struktura będzie listą lub wartościami słownikowymi powinny być krotki lub listy. –

Odpowiedz

9

Oto niezbyt przyjemny sposób na zrobienie tego. Rezultatem jest generator, ale jeśli naprawdę chcesz listę, możesz ją połączyć z numerem list(). Głównie to nie ma znaczenia.

Predykat jest funkcją, która decyduje o każdej parze klucz/wartość, jeśli słownik na liście ma ją uciąć. Domyślny akceptuje wszystkie. Jeśli nie ma pary k/v w słowniku, to jest ona odrzucana.

def filter_data(data, predicate=lambda k, v: True): 
    for d in data: 
     for k, v in d.items(): 
       if predicate(k, v): 
        yield d 


test_data = [{"key1":"value1", "key2":"value2"}, {"key1":"blabla"}, {"key1":"value1", "eh":"uh"}] 
list(filter_data(test_data, lambda k, v: k == "key1" and v == "value1")) 
# [{'key2': 'value2', 'key1': 'value1'}, {'key1': 'value1', 'eh': 'uh'}] 
+2

"nie tak piękne"? Nie zgadzać się. To jest bardzo miłe. –

+0

Dziękuję :). Myślę, że takie funkcje klatki schodowej są brzydkie. – Skurmedel

+1

@Skurmedel: Twoja funkcja jest elegancka i łatwo zobaczyć, jak działa w prostych krokach; to oszczędza czytelnikom, którzy muszą parsować skomplikowany jednolinijkowy w głowach. –

1

odpowiedź jest zbyt prosta, więc myślę, że brakuje nam niektórych informacji. W każdym razie:

result = [] 
for datadict in data: 
    for key, value in datadict.items(): 
     thefiltering() 

    if datadict.get('matchkey') == 'matchvalue': 
     result.append(datadict) 

Również "główny słownik" nie jest słownikiem, ale listą. Chciałem to wyjaśnić.

3

netto kwestii już podkreślono w innych komentarzach i odpowiedziach (wielokrotne identyczne klucze nie mogą być w dict, etc etc), oto jak ja to zrobię:

def select_sublist(list_of_dicts, **kwargs): 
    return [d for d in list_of_dicts 
      if all(d.get(k)==kwargs[k] for k in kwargs)] 

subdata = select_sublist(data, key1='value1') 
0

Zainspirowany odpowiedzią Skurmedal, podzielę to na rekursywny schemat pracy z bazą danych zagnieżdżonych słowników. W tym przypadku "rekord" to podkatalog w bagażniku. Predykat określa, które rekordy mamy po - te, które pasują do pary (klucz, wartość), gdzie te pary mogą być głęboko zagnieżdżone.

def filter_dict(the_dict, predicate=lambda k, v: True): 
    for k, v in the_dict.iteritems(): 
     if isinstance(v, dict) and _filter_dict_sub(predicate, v): 
      yield k, v 

def _filter_dict_sub(predicate, the_dict): 
    for k, v in the_dict.iteritems(): 
     if isinstance(v, dict) and filter_dict_sub(predicate, v): 
      return True 
     if predicate(k, v): 
      return True 
    return False 

Ponieważ jest to generator, może trzeba owinąć dict(filter_dict(the_dict)) aby uzyskać przefiltrowaną słownika.

0

To stara sprawa, ale z jakiegoś powodu nie ma nikogo-liner składnia odpowiedź:

{ k: v for k, v in <SOURCE_DICTIONARY>.iteritems() if <CONDITION> } 

Na przykład:

src_dict = { 1: 'a', 2: 'b', 3: 'c', 4: 'd' } 
predicate = lambda k, v: k % 2 == 0 
filtered_dict = { k: v for k, v in src_dict.iteritems() if predicate(k, v) } 

print "Source dictionary:", src_dict 
print "Filtered dictionary:", filtered_dict 

przyniesie następujące wyniki:

Source dictionary: {1: 'a', 2: 'b', 3: 'c', 4: 'd'} 
Filtered dictionary: {2: 'b', 4: 'd'} 
Powiązane problemy