Często znalazłem się wypełnianie list i dyktatów, czytając linię plików według linii.

Powiedzmy, że czytam na liście osób i ich ulubionych potraw:

ANNE      CHEESE  
ANNE      POTATO 
JOE       PEAS    
JOE       CHIPS   
JOE       FISH
BERNARD   LENTILS

Do słownika Pythona:

{
 "ANNE"   : ["CHEESE", "POTATO"], 
 "JOE"    : ["PEAS",   "CHIPS",   "FISH"],
 "BERNARD": ["LENTILS"]
}

Wzór generalny, którego używam jest odczytanie linii plików według linii, w każdym przypadku sprawdzania, jeśli klucz istnieje już przed próbą dołączenia. Dzisiaj postanowiłem uogólnić to funkcję safe_append, która stworzyłaby odpowiedni obiekt przed dołączeniem do listy lub ustawienie klucza słownika:

def safe_append(list_object, list_key, list_value, value_dict_key= None):
    # Add empty dict if it does not already exist
    if list_key not in list_object:
        if value_dict_key is not None:
            list_object[list_key] = {}
        else: 
            list_object[list_key] = []
    # Append/set value
    if value_dict_key is not None:
        list_object[list_key][value_dict_key] = list_value
    else: 
        list_object[list_key].append(list_value)
    # Return object (for chaining)
    return list_object 

# Usage: dict in dict
x = {}
safe_append(x, "a","b",value_dict_key = "c")
>>> {"a":{"c":"b"}}
# Usage: list in dict
x = []
safe_append(x, "a","b")
>>> {"a":["b"]}

Wydaje się to raczej niezdarne i brzydkie. Moje pytanie: Czy jest lepszy / więcej Pythonic Way to zrobić?

1
TDN169 18 sierpień 2014, 17:23

2 odpowiedzi

Najlepsza odpowiedź

Lepszym sposobem jest użycie defaultdict:

>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> d["hello"].append(1)
>>> d["hello"].append(2)
>>> dict(d)
{'hello':[1, 2]}
8
Ned Batchelder 18 sierpień 2014, 13:26

Jeśli wszystkie twoje wartości są listami, możesz użyć domyślnegoDict. W przeciwnym razie możesz uzyskać podobne zachowanie, łańcuchując SetDefault i dołączyć:

a = {}
for key,value in [("k1","v1"), ("k1","v2")]:
    a.setdefault(key,[]).append(value)
2
Andrew Johnson 18 sierpień 2014, 13:29