Reputation: 13145
I am executing the following sqlite command:
c.execute("SELECT surname,forename,count(*) from census_data group by surname, forename")
so that c.fetchall() is as follows:
(('Griffin','John', 7),
('Griffin','James', 23),
('Griffin','Mary',30),
('Griffith', 'John', 4),
('Griffith','Catherine', 5)
)
Is it possible to construct a dict of the following form using a dict comprehension:
{'Griffin': {'John': 7, 'James': 23, 'Mary':30}, 'Griffith': {'John':4,'Catherine':5}}
this is as far as I got:
counts = {s:(f,c) for s,f,c in c.fetchall()}
which overwrites values. Im using python 3.
Upvotes: 2
Views: 85
Reputation: 17884
Alternatively to defaultdict
you can use the dictionary method setdefault()
:
dct = {}
for k1, k2, v2 in c.fetchall():
v1 = dct.setdefault(k1, {})
v1[k2] = v2
or
for k1, k2, v2 in c.fetchall():
dct.setdefault(k1, {})[k2] = v2
Result:
{'Griffin': {'John': 7, 'James': 23, 'Mary': 30},
'Griffith': {'John': 4, 'Catherine': 5}}
Upvotes: 0
Reputation: 1847
You can solve it holding on itertools.groupby
and functools.itemgetter
.
from operator import itemgetter
from itertools import groupby
result = { name: dict(v for _, v in values) for name, values in groupby(((x[0], x[1:]) for x in c.fetchall()), itemgetter(0))}
print(result)
# {'Griffin': {'John': 7, 'James': 23, 'Mary': 30}, 'Griffith': {'John': 4, 'Catherine': 5}}
The outer loop splits the data between name and its values, that then groupby(...)
collapses by name. The inner loop simply builds a dict with the corresponding values.
Upvotes: 0
Reputation: 92874
Coming with dict comprehension though with itertools.groupby
magic:
from itertools import groupby
counts = {k: dict(_[1:] for _ in g) for k, g in groupby(c.fetchall(), key=lambda t: t[0])}
print(counts)
The output:
{'Griffin': {'John': 7, 'James': 23, 'Mary': 30}, 'Griffith': {'John': 4, 'Catherine': 5}}
Upvotes: 4
Reputation: 24279
You can use a collections.defaultdict to create the inner dicts automatically when needed:
from collections import defaultdict
data = (('Griffin','John', 7),
('Griffin','James', 23),
('Griffin','Mary',30),
('Griffith', 'John', 4),
('Griffith','Catherine', 5)
)
out = defaultdict(dict)
for (name, first, value) in data:
out[name][first] = value
# {'Griffin': {'John': 7, 'James': 23, 'Mary': 30}, 'Griffith': {'John': 4, 'Catherine': 5}}
Upvotes: 4
Reputation: 2569
Yes, with something like this.
my_query = (('Griffin','John', 7), ('Griffin','James', 23), ('Griffin','Mary',30), ('Griffith', 'John', 4), ('Griffith','Catherine', 5) )
dict_query = {}
for key1, key2, value in my_query:
if key1 not in dict_query:
dict_query[key1] = {}
dict_query[key1][key2] = value
Edit1
More elegant.
from collections import defaultdict
dict_query = defaultdict(dict)
for key1, key2, value in my_query:
dict_query[key1][key2] = value
Upvotes: 2