Skip to content Skip to sidebar Skip to footer

Group Similar Dict Entries As A Tuple Of Keys

I would like to group similar entries of a dataset. ds = {1: 'foo', 2: 'bar', 3: 'foo', 4: 'bar', 5: 'foo'} >>>tupelize_dict(ds) { (1,3,5): 'fo

Solution 1:

something like this should do the trick:

>>>from collections import defaultdict>>>ds = {1: 'foo',...2: 'bar',...3: 'foo',...4: 'bar',...5: 'foo'}>>>>>>d = defaultdict(list)>>>for k, v in ds.items():...    d[v].append(k)...>>>res = {tuple(v): k for k, v in d.items()}>>>res
{(1, 3, 5): 'foo', (2, 4): 'bar'}

Solution 2:

as well as you could do something like this.

deftupelize_dict(ds):
    cache = {}
    for key, value in ds.items():
        cache.setdefault(value, []).append(key)
    return {tuple(v): k for k, v in cache.items()}


ds = {1: 'foo',
      2: 'bar',
      3: 'foo',
      4: 'bar',
      5: 'foo'}
print(tupelize_dict(ds))

Solution 3:

Following the answer of acushner, it is possible to make it work if I can compute a hash of the content of dataset's elements.

import pickle
from collections import defaultdict

deftupelize_dict(ds):
    t = {}
    d = defaultdict(list)
    for k, v in ds.items():
        h = dumps(ds)
        t[h] = v
        d[h].append(k)

    return {tuple(v): t[k] for k, v in d.items()}   

This solution is MUCH faster than my original proposition.

To test it I made a set of big random nested dictionary and run cProfile on both implementations:

original: 204.9 secondsnew:        6.4 seconds

EDIT:

I realized the dumps does not work with some dictionaries because the keys order can internally vary for obscure reasons (see this question)

A workaround would be to order all the dicts:

import copy
import collections

deffaithfulrepr(od):
    od = od.deepcopy(od)
    ifisinstance(od, collections.Mapping):
        res = collections.OrderedDict()
        for k, v insorted(od.items()):
            res[k] = faithfulrepr(v)
        returnrepr(res)
    ifisinstance(od, list):
        for i, v inenumerate(od):
            od[i] = faithfulrepr(v)
        returnrepr(od)
    returnrepr(od)

deftupelize_dict(ds):
    taxonomy = {}
    binder = collections.defaultdict(list)
    for key, value in ds.items():
        signature = faithfulrepr(value)
        taxonomy[signature] = value
        binder[signature].append(key)
    deftu(keys):
        returntuple(sorted(keys)) iflen(keys) > 1else keys[0]
    return {tu(keys): taxonomy[s] for s, keys in binder.items()}   

Post a Comment for "Group Similar Dict Entries As A Tuple Of Keys"