用重复的字典键值拆分Python字典列表

5

假设我有一个字典列表:

foo = [
      {'host': 'localhost', 'db_name': 'test', 'table': 'partners'},
      {'host': 'localhost', 'db_name': 'test', 'table': 'users'},
      {'host': 'localhost', 'db_name': 'test', 'table': 'sales'},
      {'host': 'localhost', 'db_name': 'new', 'table': 'partners'},
      {'host': 'localhost', 'db_name': 'new', 'table': 'users'},
      {'host': 'localhost', 'db_name': 'new', 'table': 'sales'},
]

我该如何将此列表拆分为单独的列表(或列表的列表),其中'host'和'db_name'相同? 例如:

list1 = [
        {'host': 'localhost', 'db_name': 'test', 'table': 'partners'},
        {'host': 'localhost', 'db_name': 'test', 'table': 'users'},
        {'host': 'localhost', 'db_name': 'test', 'table': 'sales'},
]

list2 = [
        {'host': 'localhost', 'db_name': 'new', 'table': 'partners'},
        {'host': 'localhost', 'db_name': 'new', 'table': 'users'},
        {'host': 'localhost', 'db_name': 'new', 'table': 'sales'},
]
3个回答

11
>>> from collections import defaultdict
>>> dd = defaultdict(list)
>>> foo = [
      {'host': 'localhost', 'db_name': 'test', 'table': 'partners'},
      {'host': 'localhost', 'db_name': 'test', 'table': 'users'},
      {'host': 'localhost', 'db_name': 'test', 'table': 'sales'},
      {'host': 'localhost', 'db_name': 'new', 'table': 'partners'},
      {'host': 'localhost', 'db_name': 'new', 'table': 'users'},
      {'host': 'localhost', 'db_name': 'new', 'table': 'sales'},
]
>>> for d in foo:
        dd[(d['host'], d['db_name'])].append(d)

列表的列表是字典的值。
>>> dd.values()
[[{'table': 'partners', 'host': 'localhost', 'db_name': 'new'}, {'table': 'users', 'host': 'localhost', 'db_name': 'new'}, {'table': 'sales', 'host': 'localhost', 'db_name': 'new'}], [{'table': 'partners', 'host': 'localhost', 'db_name': 'test'}, {'table': 'users', 'host': 'localhost', 'db_name': 'test'}, {'table': 'sales', 'host': 'localhost', 'db_name': 'test'}]]

1
考虑到主机名和数据库名称的要求。 - Burhan Khalid
+1 我忽略了主机和数据库名称都是必需的这一事实。 - Ashwini Chaudhary

3
这是使用itertools中的groupby函数的完美案例:
from itertools import groupby

foo.sort(key = lambda x: (x['db_name'], x['host']))
it = groupby(foo, key = lambda x: (x['db_name'], x['host']) )

groups = []
keys = []
for k, g in it:
    groups.append(list(g))
    keys.append(k)

print groups
## >>>
##[
##    [{'table': 'partners', 'host': 'localhost', 'db_name': 'test'},
##     {'table': 'users', 'host': 'localhost', 'db_name': 'test'},
##     {'table': 'sales', 'host': 'localhost', 'db_name': 'test'}],
##    [{'table': 'partners', 'host': 'localhost', 'db_name': 'new'},
##     {'table': 'users', 'host': 'localhost', 'db_name': 'new'},
##     {'table': 'sales', 'host': 'localhost', 'db_name': 'new'}]
##]

##or make a dict
d = dict(zip(keys, groups))

只有在分组之前进行排序(或者它们已经保证排序?)。否则,在这种情况下使用 defaultdict 更合适。 - John La Rooy
@qwwqwwq 这不是完美的,因为数据没有排序,所以这是O(n log n)而不是defaultdictO(n) - jamylak
是的,没错。我在上面添加了排序步骤,因为我假设数据已经排序,但这并没有明确说明。即使进行排序,我仍然更喜欢这种方法,因为对于我所想象的使用情况,我们可以完全避免创建新的数据结构,在遍历groupby可迭代对象时优雅地处理当前的数据结构。 - qwwqwwq
@qwwqwwq 更好的方法是使用 operator.itemgetter,例如 foo.sort(key=itemgetter('db_name', 'host')) - jamylak

1
你可以这样做:
sp={}
for d in foo:
    sp.setdefault((d['host'],d['db_name']),[]).append(d)

然后打印它:
for l in sp.values():
    for d in l:
        print d
    print     


{'table': 'partners', 'host': 'localhost', 'db_name': 'new'}
{'table': 'users', 'host': 'localhost', 'db_name': 'new'}
{'table': 'sales', 'host': 'localhost', 'db_name': 'new'}

{'table': 'partners', 'host': 'localhost', 'db_name': 'test'}
{'table': 'users', 'host': 'localhost', 'db_name': 'test'}
{'table': 'sales', 'host': 'localhost', 'db_name': 'test'}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接