Home > database >  Can I reduce and sum a list straight into a dict?
Can I reduce and sum a list straight into a dict?

Time:02-16

I have a list with individual dicts, like so:

dct = [{ 'winner': 'Person A' }, { 'winner': 'Person B' }, { 'winner': 'Person B' } ...]

(the dicts have other properties, they're just not relevant).

I want to know how many times the winner was a particular string. I could do something like this:

aWins = sum((1 if d['winner'] == 'Person A' else 0) for d in dct)

then do the same for 'Person B', and maybe possibly 'Person C' if that ever comes up, etc.

However, that doesn't strike me as particularly neat or pythonic. I'm still learning all the pythonic ways of doing things (I daily drive JS, so usually I'd be doing this via reduce), so is it possible to do this more neatly? Ideally, the output is a dict that looks something like this:

{ 'Person A': 40, 'Person B': 60 }

CodePudding user response:

You can use operator.itemgetter as a mapper to extract values of the winner key of each dict. Use collections.Counter to count the number of occurrences of each value:

from collections import Counter
from operator import itemgetter

d = [{'winner': 'A'}, {'winner': 'B'}, {'winner': 'B'}]
print(dict(Counter(map(itemgetter('winner'), d))))

This outputs:

{'A': 1, 'B': 2}

CodePudding user response:

More efficient:

lst = [x['winner'] for x in dct]

print({k:lst.count(k) for k in lst})
# print({k:lst.count(k) for k in set(lst)}) # Alternatively, time-efficient but needs key sorting

Output:

{'A': 1, 'B': 2}

Highly inefficient, yet a one-liner:

dct = [{ 'winner': 'A' }, { 'winner': 'B' }, { 'winner': 'B' }]

print({k:[x['winner'] for x in dct].count(k) for k in [x['winner'] for x in dct]})

Output:

{'A': 1, 'B': 2}

CodePudding user response:

You can use pandas:

import pandas as pd
dictionary = [{ 'winner': 'Person A' }, { 'winner': 'Person B' }, { 'winner': 'Person B' }]
dataframe = pd.DataFrame.from_dict(dictionary)
number = dataframe["winner"].value_counts()

Function value_counts counts occurrences of a value (in this case, a string).

Output:

Person B    2
Person A    1
Name: winner, dtype: int64

CodePudding user response:

Using pandas:

import pandas as pd

my_dict = [
    { 'winner': 'A' },
    { 'winner': 'B' },
    { 'winner': 'B' },
    { 'winner': 'B' }
]

pd.DataFrame(data=my_dict) \
    .groupby("winner") \
    .agg(counts = ("winner", "count")) \
    .to_dict()["counts"]
# {'A': 1, 'B': 3}

CodePudding user response:

The way I would do it is to loop once over the entire list:

from collections import defaultdict

num_wins = defaultdict(int)

for d in dicts:
    num_wins[d['winner']]  = 1

Just for fun, a O(nk) one-liner, where k is the number of possible persons:

persons = list("ABC")

num_wins = {
    sum((1 if d['winner'] == person else 0) for d in dict)
    for person in persons
}

CodePudding user response:

you can iterate over the list, and see if the winner present in the iterator dict object , if yes then save that value in resultant dictionary and make count over there.

dict_ = [{ 'winner': 'Person A' }, { 'winner': 'Person B' }, { 'winner': 'Person B' }]
 
from collections import defaultdict as dd
result = dd(int)
 
for dic in dict_:
    if 'winner' in dic:
        result[dic['winner']] =1
 
print(result)
# defaultdict(<class 'int'>, {'Person A': 1, 'Person B': 2})

CodePudding user response:

How about this?

dct = [{ 'winner': 'Person A' }, { 'winner': 'Person B' }, { 'winner': 'Person B' }]

cnt_a = 0
cnt_b = 0
for i in dct:
    if str(i).count('A') >0:
        cnt_a  = 1
    elif str(i).count('B') >0:
        cnt_b  = 1
        
result = {'Person A' : cnt_a, 'Person B' : cnt_b }
result

Output:

{'Person A': 1, 'Person B': 2}
  • Related