Sc4r
Sc4r

Reputation: 700

Sum of all the values in a dictionary which contains the item in the key

Given a dictionary and a string as parameters, return a new dictionary containing the item specified as the category(second parameter, one of 'city', 'sport', 'name') as a key and it's associated value. If there are more than one occurrence of the item than take the sum of the values.

Ex.

>>> get_wins_by_category(d, 'city')
{'Toronto': 34, 'Ottawa': 45}
>>> get_wins_by_category(d, 'sport')
{'basketball': 31, 'hockey': 48}
>>> get_wins_by_category(d, 'name')
{'Raptors': 10, 'Blues': 21, 'Senators': 45, 'Leafs': 3}

What I got so far:

d = {('Raptors', 'Toronto', 'basketball'): 10,
     ('Blues', 'Toronto', 'basketball'): 21,
     ('Senators', 'Ottawa', 'hockey'): 45,
     ('Leafs', 'Toronto', 'hockey'): 3}

def get_wins_by_category(dct, category):
    new_dict = {}
    if category == 'city':
        for key in dct.keys():
            new_dict[key[1]] = #todo
    elif category == 'sport':
        for key in dct.keys():
            new_dict[key[2]] = #todo
    elif category == 'name':
        for key in dct.keys():
            new_dict[key[0]] = #todo
    return new_dict

The problem I have is what to write after the equal sign. I know that if there are more than one occurrence of the item that take the sum of all the values containing that item but I don't know how to write it as code. Also a note that the 3-tuple will always be in that order: name, city, sport.

Upvotes: 3

Views: 729

Answers (4)

jonrsharpe
jonrsharpe

Reputation: 122061

The following removes the need for the if: blocks by defining the inputs in cats

d = {('Raptors', 'Toronto', 'basketball'): 10,
     ('Blues', 'Toronto', 'basketball'): 21,
     ('Senators', 'Ottawa', 'hockey'): 45,
     ('Leafs', 'Toronto', 'hockey'): 3}

cats = ("team", "city", "sport")

def get_wins_by_category(d, cats, cat):
    if cat in cats:    
        return {t: sum(v for k, v in d.items() if t in k) 
                for t in set(key[cats.index(cat)] for key in d)}

Upvotes: 0

Ashwini Chaudhary
Ashwini Chaudhary

Reputation: 250981

Use collections.defaultdict, no if-else required:

from collections import defaultdict
def get_wins_by_category(team_to_win, category):

    d = {'name':0, 'city':1, 'sport':2}
    dic = defaultdict(int)
    for k, v in team_to_win.items():
        dic[k[d[category]]] += v
    return dic
... 
>>> get_wins_by_category(d, 'city')
defaultdict(<type 'int'>, {'Toronto': 34, 'Ottawa': 45})
>>> get_wins_by_category(d, 'sport')
defaultdict(<type 'int'>, {'basketball': 31, 'hockey': 48})
>>> get_wins_by_category(d, 'name')
defaultdict(<type 'int'>, {'Senators': 45, 'Blues': 21, 'Raptors': 10, 'Leafs': 3})

Another alternative is collections.Counter:

from collections import Counter
def get_wins_by_category(team_to_win, category):
    #index each category points to
    d = {'name':0, 'city':1, 'sport':2}
    dic = Counter()       
    for k, v in team_to_win.items():
        dic[k[d[category]]] += v
    return dic
... 
>>> get_wins_by_category(d, 'city')
Counter({'Ottawa': 45, 'Toronto': 34})
>>> get_wins_by_category(d, 'sport')
Counter({'hockey': 48, 'basketball': 31})
>>> get_wins_by_category(d, 'name')
Counter({'Senators': 45, 'Blues': 21, 'Raptors': 10, 'Leafs': 3})

Upvotes: 2

abarnert
abarnert

Reputation: 365767

Using the wrong data structure always makes your code more complicated to write, and to read, and often to run efficiently as well.

If you want to look something up by value, use a dict (or a namedtuple) with that value as a key, don't loop over the whole list and search one by one. If you need to create multiple dicts, do so.

For example:

from collections import Counter
teams, cities, sports = Counter(), Counter(), Counter()
for keys, score in d.items():
    team, city, sport = keys
    teams[team] += score
    cities[city] += score
    sports[sport] += score
categories = {'team': teams, 'city': cities, 'sport': sports}

Now your code is trivial:

def get_wins_by_category(category):
    return categories[category]

Or, alternatively, keep all the scores for each one, so you can do other things besides sum the scores (e.g., average them):

from collections import Counter
teams, cities, sports = defaultdict(list), defaultdict(list), defaultdict(list)
for keys, score in d.items():
    team, city, sport = keys
    teams[team].append(score)
    cities[city].append(score)
    sports[sport].append(score)
categories = {'team': teams, 'city': cities, 'sport': sports}

def get_wins_by_category(category):
    return {key: sum(scores) for key, scores in categories[category].items()}

def get_avg_wins_by_category(category):
    return {key: sum(scores)/len(scores) 
            for key, scores in categories[category].items()}

Upvotes: 1

Milo Wielondek
Milo Wielondek

Reputation: 4362

if category == 'city':
        for key, value in dct.items():
            new_dict[key[1]] += value

You get the point..

Upvotes: 0

Related Questions