0

我試圖將下面的代碼變成更可讀的東西。試圖將python嵌套循環轉換爲列表/ dict理解

for x in list_of_dicts: 
    for y in header: 
     if y not in x.keys(): 
      x[y] = '' 

它需要一個字典列表,並添加鍵值:值對,在默認值=「」對於那些尚未在當前字典中的任何
鍵。

我還是新來的python,所以任何幫助將不勝感激。我想:

return [x[y] = '' for x in list_of_dicts for y in header if y not in x.keys()] 

但我想你不能有「=」

+2

理解是建立一個列表,而不是執行一系列賦值語句。 –

+1

或許看看把'list_of_dicts'變成'defaultdict'的列表,以便你不必爲未定義的鍵明確填充它? – sjs

+0

'如果y不在x.keys()中' - 刪除'keys()'調用。在Python 2中,這將構建一個不必要的鍵列表,然後迭代它們以找到'y',完全放棄使用字典的好處。在Python 3中,這只是不必要的輸入。 '如果y不在x'是你想要的。 – user2357112

回答

2

這不是你的問題應該用一個列表理解來解決。使用一些集合操作上現有的代碼,你可以提高

for x in list_of_dicts: 
    x.update((y, '') for y in header.viewkeys() - x) 

這會達到同樣的效果;將缺少的header的密鑰添加爲空字符串。對於Python 3,請將viewkeys()替換爲keys()

這使得使用dictionary view objects給我們在詞典鍵上的集合式的意見;在Python 3中,此行爲現在是默認值。

如果我讀了你的問題錯了,headers是不是字典爲好,使它成爲一個明確的設定,以獲得同樣的好處:

header_set = set(header) 
for x in list_of_dicts: 
    x.update((y, '') for y in header_set.difference(x)) 

使用set操作使得代碼更易讀和高效,推動任何循環來確定設置的差異到優化的C例程中。

+1

'header'實際上可能不是字典。 – user2357112

+0

@ user2357112:確實;我可能誤解了這個問題;我推斷並可能推斷錯誤。 –

+0

假設爲每個'x'創建集合的附加工作實際上使集合差異比'不在''測試更有效或更低效率,這是相當複雜的。可能取決於它的大小?或者是在Python中對'header'進行迭代,與在C中進行迭代相比,速度慢得多,以至於不會有太多的內存分配會變慢。 –

2

不能使用字典理解將項目添加到一個字典;字典理解創建一個新的字典,從預先存在的那些獨立的,如果你想在新的和舊的結合,你必須明確這樣做,如:

for x in list_of_dicts: 
    x.update({y: '' for y in header if y not in x}) 

(注意y not in x.keys()打交道時是不必要的同類型的字典,因爲你可以做y not in x

如果你在擺脫那個外for的死心塌地,這樣做的方式,它是創造新類型的字典一個新的列表:

list_of_dicts2 = [dict(x, **{y: '' for y in header if y not in x}) for x in list_of_dicts] 
+0

很好的使用'dict()'關鍵字參數來'更新'列表理解中的新詞典! –

+1

如果鍵不是全部字符串,則第二個示例在Python 3中將不起作用。 – user2357112

+0

謝謝jwodder!我很感激幫助。 –

1

可以使用這個列表理解,但你不應該:

[x.setdefault(y, '') for x in list_of_dicts for y in header] 

的原因,你不應該的是,這將創建一個大的舊列表,你不需要但需要時間和記憶。

可以消耗發電機的理解,而無需創建一個大的舊列表:

import collections 
def consume(iterator): 
    collections.deque(iterator, maxlen = 0) 

consume(x.setdefault(y, '') for x in list_of_dicts for y in header) 

可以說你不應該這樣做,因爲相關的讀者並不真的指望內涵有副作用,因此代碼可能會嚇倒並混淆它們。

你是正確的,你不能在理解中做x[y] = '',因爲它不是一個表達式。它只是發生,x.setdefault(y, '')做你想要的,但如果沒有這種方便的功能,那麼你可以寫一個。和來想想看,這樣做就可以消除的理解,以及你的原始循環:

def set_default(x, y): 
    if y not in x: 
     x[y] = '' 

consume(itertools.starmap(set_default, itertools.product(list_of_dicts, header)) 

再次,雖然,某種警告有關使用發電機所產生的副作用可能應該適用的。

+1

這不是'None'的大列表,因爲'setdefault'返回鍵的值,但它是一個很大的不必要的清單。 – user2357112

+0

@ user2357112:好點,固定。 –

1

有很多方法可以做得更好。通過更好地思考你正在嘗試做什麼的主要原因。

你在做什麼?你可以這樣想:你想給某些字典添加默認值。 dict.setdefault()方法立即想到:

for d in list_of_dicts: 
    for h in header: 
     d.setdefault(h, '') 

你可以認爲略微別的辦法:有一組缺省值,我需要適用於所有類型的字典的。現在,首先構建defaults字典,然後合併,感覺自然:

defaults = dict.fromkeys(header, '') 
list_of_dicts = [dict(defaults, **d) for d in list_of_dicts] 

請注意,我們在這裏重建每個字典不更新它。這是使用理解時的正確方法。在這裏添加的一件事是,將最後一行與代碼構造list_of_dicts合併可能是有意義的(我不能肯定地說沒有看到)。

+0

列表理解的確假定'd'中的所有鍵都是字符串,但'defaults'設置是一個不錯的方法! –

+0

不,不是。在python控制檯中試試這個'dict({},** {None:1})''。 – Suor

+0

現在在Python 3中嘗試:-) –

0
>>> d1={'a':1} 
>>> d2={'b':2} 
>>> d3={'c':3} 
>>> listofdict=[d1, d2, d3] 
>>> listofdict 
[{'a': 1}, {'b': 2}, {'c': 3}] 
>>> header = ['x', 'y'] 
>>> header 
['x', 'y'] 
>>> [ x.update({k:''}) for x in listofdict for k in header if not x.get(k) ] 
[None, None, None, None, None, None] 
>>> listofdict 
[{'a': 1, 'x': '', 'y': ''}, {'y': '', 'x': '', 'b': 2}, {'y': '', 'x': '', 'c': 3}] 
>>> d1 
{'a': 1, 'x': '', 'y': ''} 
>>> d2 
{'y': '', 'x': '', 'b': 2} 
>>> d3 
{'y': '', 'x': '', 'c': 3} 
>>>