2010-01-12 62 views
27

我正在瀏覽一大堆具有多對多關係的元組,並且我想創建一個字典,其中每個b(a,b)都有一個與b對應的所有a的列表。在字典的關鍵字b處測試一個列表似乎很尷尬,然後尋找一個a,然後在每次通過元組消化循環時追加一個,如果它不在那裏的話;但我還沒有找到更好的方法。有一個存在嗎?有沒有其他方法可以做到這一點更漂亮?有效的方法來創建一個列表,或者如果一個已經存在的話追加到它?

+1

或算法? – 2010-01-12 20:56:44

回答

36

setdefault()方法見the docs

setdefault(鍵[默認])
如果鍵是在詞典 ,返回其值。 如果不是,插入鍵值爲 默認並返回默認值。默認 默認爲無。

您可以使用此作爲一個單一的呼叫將得到B如果它存在,或者設置b鍵空列表,如果它不存在 - 而無論哪種方式,回報B:

>>> key = 'b' 
>>> val = 'a' 
>>> print d 
{} 
>>> d.setdefault(key, []).append(val) 
>>> print d 
{'b': ['a']} 
>>> d.setdefault(key, []).append('zee') 
>>> print d 
{'b': ['a', 'zee']} 

「在沒有」檢查用一個簡單的結合這一點,你做你的三條線後在做什麼:

>>> b = d.setdefault('b', []) 
>>> if val not in b: 
... b.append(val) 
... 
>>> print d 
{'b': ['a', 'zee', 'c']} 
+3

假設你有Python 2.5或更高版本,'defaultdict'比'setdefault'好一點。 – ephemient 2010-01-12 20:51:41

+1

我被困在2.34,所以這實際上是答案,對我來說 - 謝謝,詹姆斯! – user249228 2010-01-13 15:54:32

+5

D'oh。 'set()'很好,但是直到2.4才建成。你的Python爲什麼這麼老? :-( – ephemient 2010-01-15 05:13:36

2

你可以整理你的元組爲O(n log n)的再創造你的字典爲O(n)

或simplier爲O(n),但可能會強加內存重載很多元組的情況下:

your_dict = {} 
for (a,b) in your_list: 
    if b in your_dict: 
     your_dict[b].append(a) 
    else: 
     your_dict[b]=[a] 

嗯它幾乎和你所描述的一樣。這有什麼尷尬的?

你也可以考慮使用sql數據庫來做骯髒的工作。

+0

順便說一下,更簡單的方法是O(n),所以最好對元組進行排序。 – kennytm 2010-01-12 20:37:04

+0

是的,我也在編輯過的版本中說過。 – 2010-01-12 20:57:32

+0

關於downvoting的任何意見? – 2010-01-12 21:00:13

0

我不知道你將如何走出關鍵的考驗,但一旦他們鍵/值對已被初始化很容易:)

d = {} 
if 'b' not in d: 
    d['b'] = set() 
d['b'].add('a') 

設定將確保只有「1 '在收藏中。您需要進行初始'b'檢查,以確保鍵/值存在。

+0

好奇爲什麼-1?不知怎的,這是錯誤的?如果錯誤,我會刪除答案。 – 2010-01-14 16:45:23

15

假設你沒有真正捆綁到列表,defaultdictset都相當方便。

import collections 
d = collections.defaultdict(set) 
for a, b in mappings: 
    d[b].add(a) 

如果你真的想列表,而不是套,你可以按照這個有

for k, v in d.iteritems(): 
    d[k] = list(v) 

如果你真的想要一個字典,而不是一個defaultdict,你可以說

d = dict(d) 

雖然我並沒有真正看到你想要的任何理由。

+0

啊是的,這樣可以避免初始檢查沒有任何價值,謝謝!我學到了一些新的東西:) – 2010-01-12 20:51:09

+1

對於'defaultdict'來說+1,因爲它確實是最爲Pythonic的解決方案。 – jathanism 2010-01-12 21:56:45

+1

我也很喜歡[這個人幫我拿出defaultdict(lambda:defaultdict(list))](http://ohuiginn.net/mt/2010/07/nested_dictionaries_in_python.html) – lkraav 2013-07-22 21:40:29

4

使用集合。defaultdict

your_dict = defaultdict(list) 
for (a,b) in your_list: 
    your_dict[b].append(a) 
+0

你是不是想要用'append'? – interjay 2010-01-12 20:47:35

+0

是的,我確實是這個意思。謝謝 – 2010-01-12 20:51:12

+0

OP的「然後附加一個,如果它不在那裏」讓我覺得原來的列表可能有重複的應該被過濾掉,這就是爲什麼我使用'set'而不是'list'。 – ephemient 2010-01-12 21:12:49

3

代替使用if的,AFAIK更Python化使用try塊來代替。

your_list=[('a',1),('a',3),('b',1),('f',1),('a',2),('z',1)] 

your_dict={} 
for (a,b) in your_list: 
    try: 
     your_dict[b].append(a) 
    except KeyError: 
     your_dict[b]=[a] 

print your_dict 
0

字典get方法嗎? 它返回的my_dict[some_key]的值,如果some_key在字典中,如果沒有 - (在下面的例子中[])返回一些默認值:

my_dict[some_key] = my_dict.get(some_key, []).append(something_else) 
0

還有另一種方式,是相當有效的(雖然也許還不如高效套)和簡單。它在實踐上與defaultdict類似,但不需要額外的導入。 如果您有一個帶空(無)鍵的字典,則表示您還在某處創建了字典鍵。您可以使用dict.fromkeys方法執行此操作,並且此方法還允許爲所有鍵設置默認值。

keylist = ['key1', 'key2'] 
result = dict.fromkeys(keylist, []) 

其中result將是: { '鍵1':[], 'KEY2':[]}

然後,你可以做你的循環和漂亮,你的意思是語法使用result['key1'].append(..)直接

相關問題