2010-01-12 61 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(..)直接

相关问题