Gaz Zhao
Gaz Zhao

Reputation: 39

Group all keys with the same value in a dictionary of sets

I am trying to transform a dictionary of sets as the values with duplication to a dictionary with the unique sets as the value and at the same time join the keys together.

dic = {'a': {1, 2, 3}, 'b': {1, 2}, 'c': {1, 3, 2}, 'd': {1, 2, 3}}

Should be changed to

{'a-c-d': {1, 2, 3}, 'b': {1, 2}}

My try is as below, but I think there has to be a better way.

def transform_dictionary(dic: dict) -> dict:
    dic = {k: frozenset(v) for k, v in dic.items()}
    key_list = list(dic.keys())
    value_list = list(dic.values())
    dict_transformed = {}   
    for v_uinque in set(value_list):
        sub_key_list = []
        for i, v in enumerate(value_list):
            if v == v_uinque:
                sub_key_list.append(str(key_list[i]))
        dict_transformed['-'.join(sub_key_list)] = set(v_uinque)
    return dict_transformed

print(transform_dictionary(dic))

Upvotes: 3

Views: 763

Answers (2)

AKX
AKX

Reputation: 168863

You can "invert" the input dictionary into a dictionary mapping frozensets into a set of keys.

import collections

dic = {'a': {1, 2, 3}, 'b': {1, 2}, 'c': {1, 3, 2}, 'd': {1, 2, 3}}

keys_per_set = collections.defaultdict(list)
for key, value in dic.items():
    keys_per_set[frozenset(value)].append(key)

Then invert that dictionary mapping back into the desired form:

{'-'.join(keys): value for (value, keys) in keys_per_set.items()}

Output:

{'a-c-d': frozenset({1, 2, 3}), 'b': frozenset({1, 2})}

This will turn the values into a frozenset, but you could "thaw" them with a set(value) in the last list comprehension.

Upvotes: 6

Chris
Chris

Reputation: 16147

from itertools import groupby
dic_output = {'-'.join(v):g for g,v in groupby(sorted(dic_input,
                                     key=dic_input.get),
                              key=lambda x: dic_input[x])}

Output

{'b': {1, 2}, 'a-c-d': {1, 2, 3}}

Upvotes: -1

Related Questions