MediumLINQNot started

Staff per department

A hospital roster lists one staff member per line as a name followed by a department. Management wants a headcount per department, with the busiest department first. Where two departments have the same headcount, list them in alphabetical order.

Read the roster, group it by department and print the counts.

Input

The first line is an integer n. Each of the next n lines is name department, two words of lower-case letters separated by one space.

Output

One line per distinct department in the form department: count, ordered by count descending, then by department name ascending.

Example 1

Input

6
mara surgery
tomas radiology
ines surgery
kofi pharmacy
lena radiology
omar surgery

Output

surgery: 3
radiology: 2
pharmacy: 1

Surgery has three people, radiology two and pharmacy one.

Example 2

Input

3
abe wards
bea theatre
cal reception

Output

reception: 1
theatre: 1
wards: 1

All three departments tie on one person each, so they are listed alphabetically.

Constraints

  • 1 <= n <= 200
  • Names and departments are 1 to 20 lower-case letters

Hints

Hint 1 of 3

You only need the department from each line, so store just parts[1].

Hint 2 of 3

GroupBy(d => d) gives one group per distinct department; each group has a Key and a Count().

Hint 3 of 3

Chain OrderByDescending(count) and then ThenBy(name) so the alphabetical order only decides ties.

Solution

Show a reference solution and explanation
 C# · reference solution
int count = int.Parse(Console.ReadLine()!);
var departments = new List<string>();
for (int i = 0; i < count; i++)
{
    string[] parts = Console.ReadLine()!.Split(' ');
    departments.Add(parts[1]);
}

var ranked = departments
    .GroupBy(d => d)
    .Select(g => new { Name = g.Key, Count = g.Count() })
    .OrderByDescending(x => x.Count)
    .ThenBy(x => x.Name, StringComparer.Ordinal);

foreach (var entry in ranked)
{
    Console.WriteLine($"{entry.Name}: {entry.Count}");
}

Why it works

LINQ expresses the whole report as a pipeline: group, project each group to a name and a count, then sort. OrderByDescending followed by ThenBy is the idiom for a primary key with a tie-breaker; a second OrderBy instead of ThenBy would throw the first ordering away. Passing StringComparer.Ordinal makes the alphabetical order depend only on character codes, not on the machine's culture settings, which is what you want for reproducible output. The query is lazy: nothing is grouped or sorted until the foreach starts pulling results.

Your program
int count = int.Parse(Console.ReadLine()!);
var departments = new List<string>();
for (int i = 0; i < count; i++)
{
    string[] parts = Console.ReadLine()!.Split(' ');
    departments.Add(parts[1]);
}

// group the departments, order the groups and print "department: count"
Run is not available for C# in the browser yet. Write your program here, then download it and run it locally with .NET SDK 8.0 against the examples above. The reference solution below was verified the same way.

Tests: 6 cases including the examples. Passing every test marks the exercise solved in this browser.

How this page was checked. Every program on it was run with .NET SDK 8.0 at build time by the publishing checks, and the output shown is what it printed. Running C# inside the browser is not available yet, so the Run button is absent rather than pretending; copy the code and run it with .NET SDK 8.0 locally.