Brandon
Brandon

Reputation: 3

Print a list of every combination of dictionary keys with the associated sum of the key values to the right

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

Answers (4)

ospahiu
ospahiu

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

akuiper
akuiper

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

Ilja Everilä
Ilja Everilä

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

drjackild
drjackild

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

Related Questions