Reputation: 3
I have several dictionaries and I want to print a table where each row is a unique combination of the keys in all dictionaries. For each row, I also want to print the sum of the values for the keys in that particular combination.
So, if I have these dictionaries:
dict1 = {"Main": 8, "Optional": 6, "Obscure": 4}
dict2 = {"Global": 8, "Regional": 4, "Local": 2}
...
The output would look like this (sorted by sum highest to lowest):
Main, Global, 16
Optional, Global, 14
Main, Regional, 12
Obscure, Global, 12
Main, Local, 10
Optional, Regional, 10
Optional, Local, 8
Obscure, Regional, 8
Obscure, Local, 6
From what I've read, itertools.product will be what I'm looking for, but none of the existing questions are quite my use case and I'm struggling to even get started.
Any help would be appreciated.
Thanks
Upvotes: 0
Views: 909
Reputation: 3525
This method is built to support a variable amount of dictionaries. You pass your dictionaries to the get_product_sums()
method, which then creates a cartesian product from the tuple of dictionaries.
We then iterate through our new subitem
to calculate sums by doing a look up in our flattened
which is just a 1D dictionary now. We then sort by the sum, and return a sorted list of tuples for our final result
.
from itertools import product
def get_product_sums(* args):
result = []
flattened = {k:v for d in args for k, v in d.items()}
for subitem in product(* args, repeat=1):
data = subitem + (sum(flattened[key] for key in subitem),)
result.append(data)
return sorted(result, key=lambda x: x[-1], reverse=True)
Sample Output:
>>> dict1 = {"Global": 8, "Regional": 4, "Local": 2}
>>> dict2 = {"Main": 8, "Optional": 6, "Obscure": 4}
>>> for item in get_product_sums(dict1, dict2):
... print ', '.join(str(element) for element in item)
Global, Main, 16
Global, Optional, 14
Global, Obscure, 12
Regional, Main, 12
Local, Main, 10
Regional, Optional, 10
Local, Optional, 8
Regional, Obscure, 8
Local, Obscure, 6
Upvotes: 0
Reputation: 214987
Use product
from itertools
on the dictionary items() where you can get the both key and value at the same time, and with the combination of key-value pairs you can construct the final result pretty straightforwardly:
from itertools import product
sorted([(k1, k2, v1+v2) for (k1, v1), (k2, v2) in product(dict1.items(), dict2.items())], \
key = lambda x: x[2], reverse=True)
# [('Main', 'Global', 16),
# ('Optional', 'Global', 14),
# ('Obscure', 'Global', 12),
# ('Main', 'Regional', 12),
# ('Main', 'Local', 10),
# ('Optional', 'Regional', 10),
# ('Obscure', 'Regional', 8),
# ('Optional', 'Local', 8),
# ('Obscure', 'Local', 6)]
Upvotes: 1
Reputation: 52949
You've read right. Just add sorted()
:
from itertools import product
from operator import itemgetter
results = [(k1, k2, dict1[k1] + dict2[k2])
for k1, k2 in product(dict1.keys(), dict2.keys())]
for k1, k2, sum_ in sorted(results, key=itemgetter(2), reverse=True):
print(k1, k2, sum_, sep=', ')
Upvotes: 0
Reputation: 472
I think this would be something like:
import itertools
dict1 = {"Main": 8, "Optional": 6, "Obscure": 4}
dict2 = {"Global": 8, "Regional": 4, "Local": 2}
merged = {'{}, {}'.format(prod[0], prod[1]): dict1[prod[0]] + dict2[prod[1]]
for prod in itertools.product(dict1, dict2)}
for k, v in merged.items():
print('{}: {}'.format(k, v))
Output:
Optional, Regional: 10
Main, Regional: 12
Optional, Local: 8
Main, Global: 16
Optional, Global: 14
Main, Local: 10
Obscure, Regional: 8
Obscure, Global: 12
Obscure, Local: 6
Upvotes: 1