写一个python列表生成

如何将
[(a, 1), (b, 2), (a, 3)]
转成
{
a: [1, 3]
b: [2]
}

想用一个列表生成来做,有什么好的方法么?

阅读 4k
7 个回答

感谢各位的回答,我找到一个比较好的备选方案

>>> from itertools import groupby
>>> from operator import itemgetter
>>> lst = [("a", 1), ("b", 2), ("a", 3)]
>>> {k: list(map(itemgetter(1), g)) for k, g in groupby(sorted(lst, key=itemgetter(0)), key=itemgetter(0))}
{'a': [1, 3], 'b': [2]}

不是一个列表生成的:

from collections import defaultdict
s = [('a', 1), ('b', 2), ('a', 3)]
d = defaultdict(list)
for k, v in s:
    d[k].append(v)
print(d.items())
s = [('a', 1), ('b', 2), ('a', 3)]
l = {'a':[i[1] for i in s if i[0] == 'a'],
     'b':[i[1] for i in s if i[0] == 'b']
     }

这个意思?

这个多像mapreduce的map操作

《流畅的Python》中第 80 页,也就是第三章的 3.9.3 小节内容 —— 《dict 的实现及其导致的结果》中明确提到:

  • 不要对字典同时进行个迭代和修改。你的需求,此处使用字典生成式,会触及到此处,会形成意想不到的问题。{k:[].append(v) for k, v in [('a', 1), ('b', 2), ('a', 3)]}
  • 如果非要这样,那么先对字典迭代,以得出需要添加的内容,把这些内容放在一个新字典里,迭代结束后,再对原有字典进行更新。建议你使用 @vibiu @Lin_R 的版本。

这主要由于 dict 的实现方式确定的,建议有空看看“散列冲突”的问题。

个人觉得 列表生成不适合用来做这些操作, 规范点会比较好

from collections import defaultdict

result = defaultdict(list)
s = [('a', 1), ('b', 2), ('a', 3)]
for i in s:
    result[i[0]].append(i[1])

我还没想到比

l = [('a', 1), ('b', 2), ('a', 3)]
d = {}
for k, v in l:
    d.setdefault(k, []).append(v)    
print(d)

更简洁的方法。
强求使用字典推导,写出冗长的一行,就像初学英语滥用从句。也许作为思维训练有意义,从实用和代码审美上没有意义。
效率上讲,中间绕了很大一个圈子,嵌套的高阶函数调用,很是浪费。
至于 @藕丝空间 说的,我觉得楼主的写法并不是这个问题,楼主的推导式写法是在创建字典时展开grouby处理好的生成器,并不是迭代时修改。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题