Python concatenates dictionary keys and values using comprehension
HOW TO CONSULT the following with python COMPREHENSION
FROM (list of dicts)
[
{'server':'serv1','os':'Linux','archive':'/my/folder1'}
,{'server':'serv2','os':'Linux','archive':'/my/folder1'}
,{'server':'serv3','os':'Linux','archive':'/my/folder2'}
,{'server':'serv4','os':'AIX','archive':'/my/folder1'}
,{'server':'serv5','os':'AIX','archive':'/my/folder1'}
]
TO (a list of dicts with a tuple as a key and a list of "server # as value
[
{('Linux','/my/folder1'):['serv1','serv2']}
,('Linux','/my/folder2'):['serv3']}
.{('AIX','/my/folder1'):['serv4','serv5']}
]
source to share
having to be able to set default values for your dictionary and have the same key multiple times can lead to some inconvenience. i would prefer something like this:
a defaultdict
might help:
from collections import defaultdict
lst = [
{'server':'serv1','os':'Linux','archive':'/my/folder1'},
{'server':'serv2','os':'Linux','archive':'/my/folder1'},
{'server':'serv3','os':'Linux','archive':'/my/folder2'},
{'server':'serv4','os':'AIX','archive':'/my/folder1'},
{'server':'serv5','os':'AIX','archive':'/my/folder1'}
]
dct = defaultdict(list)
for d in lst:
key = d['os'], d['archive']
dct[key].append(d['server'])
If you prefer to have a standard dictionary at the end (in fact, I really don't see a good enough reason for this), you can use dict.setdefault
to create an empty list where the key doesn't exist yet:
dct = {}
for d in lst:
key = d['os'], d['archive']
dct.setdefault(key, []).append(d['server'])
documentation on defaultdict
(vs. setdefault
) :
This method is simpler and faster than the equivalent technique using dict.setdefault ()
source to share
Difficult to achieve with list comprehension due to the accumulation effect. However, it can be used itertools.groupby
in a list sorted by your keys (use the same function key
for sorting and grouping).
Then, extract the server information in concept and list prefix using a group key. Pass the resulting (group key, server list) into the dictionary comprehension and here you go.
import itertools
lst = [
{'server':'serv1','os':'Linux','archive':'/my/folder1'}
,{'server':'serv2','os':'Linux','archive':'/my/folder1'}
,{'server':'serv3','os':'Linux','archive':'/my/folder2'}
,{'server':'serv4','os':'AIX','archive':'/my/folder1'}
,{'server':'serv5','os':'AIX','archive':'/my/folder1'}
]
sortfunc = lambda x : (x['os'],x['archive'])
result = {k:[x['server'] for x in v] for k,v in itertools.groupby(sorted(lst,key=sortfunc),key = sortfunc)}
print(result)
I get:
{('Linux', '/my/folder1'): ['serv1', 'serv2'], ('AIX', '/my/folder1'): ['serv4', 'serv5'], ('Linux', '/my/folder2'): ['serv3']}
Keep in mind that this is not because it can be written on one line, but that it is more efficient. The approach defaultdict
doesn't require sorting, for example.
source to share