Skip to content
UniCircle
MediumCodingParsing and aggregation

Topper and average for each subject from CSV rows

Question PY-DAT-105

Each row is name,subject,marks. For every subject, in alphabetical order, print:

  • the topper: the highest mark; if two students tie, the alphabetically smaller name;
  • the topper's mark;
  • the average mark for the subject, with exactly 2 decimal places.

Constraints

  • 1 ≤ n ≤ 10^4

Input and output

Input
First line: n. Then n lines `name,subject,marks` (marks are integers from 0 to 100; no spaces).
Output
One line per subject: `subject topper marks average`.

Examples

Input 1

6
Riya,maths,91
Dev,maths,91
Arjun,physics,78
Riya,physics,64
Dev,dsa,88
Tara,maths,70

Output

dsa Dev 88 88.00
maths Dev 91 84.00
physics Arjun 78 71.00

Dev and Riya tie on 91 in maths; Dev comes first alphabetically. The maths average is (91 + 91 + 70) / 3 = 84.00.

Input 2

2
Sana,os,0
Neha,os,1

Output

os Neha 1 0.50

A 0 is a valid mark. The average is 0.50.

Show hints
  • Keep one running record per subject: the best (marks, name), the total and the count.
  • To compare "highest mark, then smallest name" with one max, use the key (marks, reversed name order). Or compare tuples by hand.
Show the explanation

Make one pass and keep a small record per subject:

Python
best = {}                       # subject -> (marks, name)
total, count = defaultdict(int), defaultdict(int)
for row in rows:
    name, subject, m = row.split(",")
    m = int(m)
    total[subject] += m
    count[subject] += 1
    cur = best.get(subject)
    if cur is None or m > cur[0] or (m == cur[0] and name < cur[1]):
        best[subject] = (m, name)

Then for each subject in sorted(best), print the topper and f"{total[subject] / count[subject]:.2f}".

Discussion points

  • One pass, O(n) memory per subject at most. The rows do not need to be stored, so the same code works on a file streamed line by line: for line in open(path).
  • Tie-breaking. The rule "highest marks, then smallest name" mixes descending and ascending order. Write the comparison explicitly, or sort with key=lambda r: (-r.marks, r.name) and take the first row.
  • Real CSV files can contain quoted commas. Then use the csv module (csv.reader) rather than split(","). In data work, pandas.read_csv with groupby("subject").agg(...) does this in two lines. Interviewers often ask for both versions.
  • Formatting: :.2f rounds the floating-point value. Values exactly halfway between two outputs can depend on binary representation. For money, use decimal.Decimal.

Original UniCircle question. Last reviewed 22 Oct 2026.