Search code examples
pythonlisttuplesdefaultdict

How to count unique key elements in a tuple in a defaultdict (python)?


I have the following dictionary, keys being tuples:

 defaultdict(<class 'float'>, {('abc', 'xyz'): 1.0, ('abc', 'def'):
 3.0, ('abc', 'pqr'): 1.0, ('pqr', 'xyz'): 1.0, ('pqr', 'def'): 1.0})

How do I count up the first key element and second key element, so that I can get:

defaultdict(<class 'float'>, {'abc': 3.0, 'pqr': 3.0})

and

defaultdict(<class 'float'>, {'xyz': 2.0, 'def': 2.0, 'pqr': 1.0})

I am ignoring the values in the original dictionary and just counting up unique keys (first and second separately).

I want to do something like the following, but I get an error "'tuple' object has no attribute 'items'":

first_key_list =[j[0][0] for i in dictionary for j in i.items()]
new_dict = collections.defaultdict(float)
for i in first_key_list:
    new_dict[i] += 1

Solution

  • for i in dictionary for j in i.items() doesn't work because outer loop yields the dictionary keys (the tuples), and items don't apply to tuples.

    Anyway, it seems that you're ignoring the values of your dictionaries. Just use collections.Counter on the first part of the key:

    d = {('abc', 'xyz'): 1.0, ('abc', 'def'):
     3.0, ('abc', 'pqr'): 1.0, ('pqr', 'xyz'): 1.0, ('pqr', 'def'): 1.0}
    
    import collections
    
    d1 = collections.Counter(k[0] for k in d)
    
    print(d1)
    

    result:

    Counter({'abc': 3, 'pqr': 2})
    

    if you want floats, I suggest that you convert to float after having counted to avoid floating point inaccuracy:

    {k:float(v) for k,v in d1.items()}
    

    or in one line:

    d1 = {k:float(v) for k,v in collections.Counter(k[0] for k in d).items()}
    

    to keep keys as tuples:

    d1 = {(k,):float(v) for k,v in collections.Counter(k[0] for k in d).items()}
    

    for the second part, just use k[1] instead.