Python3: Get count for same dictionaries within list

Viewed 39

I have a list of dictionaries and want to get the unique dictionaries with count. i.e

[{'Basic': 100},
{'Basic': 100},
{'Basic': 100, 'Food Allowance': 1000},
{'Basic': 100, 'Food Allowance': 1000},
{'Basic': 100},
{'Basic': 100, 'Food Allowance': 1000},
{'Basic': 200}]

Out put should be like

{'Basic': 100} -> 3
{'Basic': 100, 'Food Allowance': 1000} -> 3
{'Basic': 200} -> 1

OR

[index_no] -> count
6 Answers

Using collections.Counter

  • Dictionary is not hashable so must convert each to a tuple
  • Sort dictionary key, value pairs so initial order does not matter in each dictionary

Code

from collections import Counter

lst = [{'Basic': 100},
{'Basic': 100},
{'Basic': 100, 'Food Allowance': 1000},
{'Basic': 100, 'Food Allowance': 1000},
{'Basic': 100},
{'Basic': 100, 'Food Allowance': 1000},
{'Basic': 200}]

# Output count of each dictionary
Counter([tuple(sorted(d.items())) for d in lst])

Output

Counter({(('Basic', 100),): 3,
         (('Basic', 100), ('Food Allowance', 1000)): 3,
         (('Basic', 200),): 1})

A quick and dirty solution would be to loop over the list of dictionaries and save each unique one and keep a counter. Something like this:

def count_and_set_dict(dict):
    set_dict = []
    count_dict = []

    for d in dict:
        if d not in set_dict:
            set_dict.append(d)
            count_dict.append(1)
        else:
            count_dict[set_dict.index(d)] += 1

    for i in range(len(set_dict)):
        print(f"{set_dict[i]} --> {count_dict[i]}")

dicts = [{'Basic': 100},
{'Basic': 100},
{'Basic': 100, 'Food Allowance': 1000},
{'Basic': 100, 'Food Allowance': 1000},
{'Basic': 100},
{'Basic': 100, 'Food Allowance': 1000},
{'Basic': 200}]

count_and_set_dict(dicts)

Output

{'Basic': 100} --> 3
{'Basic': 100, 'Food Allowance': 1000} --> 3
{'Basic': 200} --> 1

My approach is getting unique dictionaries in the list and counting the elements in the original list by count()

dictlist = [{'Basic': 100},
{'Basic': 100},
{'Basic': 100, 'Food Allowance': 1000},
{'Basic': 100, 'Food Allowance': 1000},
{'Basic': 100},
{'Basic': 100, 'Food Allowance': 1000},
{'Basic': 200}]

unique_dictlist = list(map(dict, set(tuple(sorted(sub.items())) for sub in dictlist))) #to get only unique values.
for d in unique_dictlist:
    print(d,"-->",dictlist.count(d))

result:

{'Basic': 200} -> 1
{'Basic': 100, 'Food Allowance': 1000} -> 3
{'Basic': 100} -> 3

You can use collections.Counter, however, it requires the list elements to be hashable, which dictionaries are clearly not. One solution might be converting your dictionaries to 'string dictionaries':

from collections import Counter
Counter([str(i) for i in your_list])

will return:

Counter({"{'Basic': 100}": 3,
     "{'Basic': 100, 'Food Allowance': 1000}": 3,
     "{'Basic': 200}": 1})

or:

list(Counter(your_list).items())

will give

[("{'Basic': 100}", 3),
 ("{'Basic': 100, 'Food Allowance': 1000}", 3),
 ("{'Basic': 200}", 1)]

We must specify our purpose There are different ways to do this

  • If the order of the keys in each dictionary is the same, you can compare them
  • If the order of the keys is not the same, you can arrange it
  • If you don't want to sort, you can create a key with the values in it and compare the key

    b100
    b100
    b100f1000
    b100f1000
    b100
    b100f1000
    b100

Or use data classes(no need to order dict):

from dataclasses import dataclass
from typing import Optional

datas = [{'Basic': 100},
{'Basic': 100},
{'Basic': 100, 'FoodAllowance': 1000},
{'Basic': 100, 'FoodAllowance': 1000},
{'Basic': 100},
{'Basic': 100, 'FoodAllowance': 1000},
{'Basic': 200}]

@dataclass(order=True)
class BaseDataClass:
    Basic: int = None
    FoodAllowance: Optional[int] = None

objects = []
for data in datas:
    objects.append(BaseDataClass(**data))

print(objects[3]==objects[2])

from collections import Counter
Counter([str(object) for object in objects])

Here, my simple logic is to find the unique values using set() and then find out how many time it repeat using .count().

More, I have convert dict values to string and convert again i am using ast package.

Code:

import ast
for i in set([str(d) for d in df1]):
    print(i + ' -> '+ str(df1.count(ast.literal_eval(i))))

Output:

{'Basic': 100, 'Food Allowance': 1000} -> 3
{'Basic': 100} -> 3
{'Basic': 200} -> 1

To dict:

import ast
tmp = {}
for i in set([str(d) for d in df1]):
    tmp[i] = df1.count(ast.literal_eval(i))

Output:

{"{'Basic': 100, 'Food Allowance': 1000}": 3,
 "{'Basic': 100}": 3,
 "{'Basic': 200}": 1}
Related