Finding Max aggregate of list of Tuples

Write a Python function maxaggregate(l) that takes a list of pairs of the form (name,score) as argument, where name is a string and score is an integer. Each pair is to be interpreted as the score of the named player. For instance, an input of the form [('Kohli',73),('Ashwin',33),('Kohli',7),('Pujara',122),('Ashwin',90)] represents two scores of 73 and 7 for Kohli, two scores of 33 and 90 for Ashwin and one score of 122 for Pujara. Your function should compute the players who have the highest aggregate score (aggegrate = total, so add up all scores for that name) and return the list of names of these players as a list, sorted in alphabetical order. If there is a single player, the list will contain a single name.

For instance:

maxaggregate([('Kohli',73),('Ashwin',33),('Kohli',7),('Pujara',122),('Ashwin',90)]) 

should return:

['Ashwin']

because the aggregate score of Kolhi is 80, of Ashwin is 123 and of Pujara is 122, of which 123 is the highest.

def maxaggregate(l):
  d = {}
  for i in l:
    if i[0] in d:
      d[i[0]] += i[1]
    else:
      d[i[0]] = i[1]
  m = max(list(d.values()))
  x = []
  for i in d:
    if d[i] == m:
      x.append(i)
  return sorted(x)

Upvotes: 0

Views: 956

Answers (3)

I would probably use a defaultdict:

from collections import defaultdict
def maxaggregate(lst):
    # If a key is not in the dict it will
    # default the value for that key to 0 (the default int).
    d = defaultdict(int)

    # Sum up the scores
    for name, score in lst:
        d[name] += score

    # Return the max score by iterating
    # over the defaultdict's items and finding
    # the max score (the 2nd element 
    #     in the item is the score thus the x[1]).
    return max(d.items(), key=lambda x: x[1])

r = maxaggregate([('Kohli',73),('Ashwin',33),('Kohli',7),('Pujara',122),('Ashwin',90)]) 
print(r) # ('Ashwin', 123)

Upvotes: 2

palvarez
palvarez

Reputation: 1598

You can iterate over the list, create a dict to keep the scores and add up the scores by name. Then keeping note of the highest score you find with the associated name.

def maxaggregate(scores):
  agg_results = {}
  max_name = None
  max_val = None
  for name, score in scores:
    score += agg_results.get(name, 0)       # Add up the score
    agg_results[name] = score               # Save it in the dict
    if max_val is None or max_val < score:  # Compare scores
      max_val = score
      max_name = name
  return name

print(maxaggregate([('Kohli',73),('Ashwin',33),('Kohli',7),('Pujara',122),('Ashwin',90)]))

Returns: Ashwin

This solution only iterates over the list once.

Upvotes: 1

user2390182
user2390182

Reputation: 73460

You can do the following, using a collections.Counter and itertools.takewhile:

from collections import Counter
from itertools import takewhile

def maxaggregate(l):
    c = Counter()
    for k, v in l:
        c[k] += v
    mc = c.most_common()
    max_count = mc[0][1]
    return sorted(name for name, _ in takewhile(lambda i: i[1] == max_count, mc))

Upvotes: 0

Related Questions