Definition
- groupingBy(getCity, counting()) produces
Mapof headcount per city. - max(comparingByValue()) on the entrySet finds the city with the highest count.
- Same pattern as department-with-most-employees, just grouped by city instead.
- Ties: find maxCount, then filter all entries matching it.
The bank wants to know which city has the most employees. Count employees per city, then pick the city with the highest count.
Understanding the Concepts
How do you find the most common city?
package com.bank.hr;
import java.util.*;
import java.util.stream.Collectors;
public class MostCommonCity {
public static void main(String[] args) {
List<Employee> employees = Employee.getSampleEmployees();
Map<String, Long> countByCity = employees.stream()
.collect(Collectors.groupingBy(
Employee::getCity, Collectors.counting()));
Optional<Map.Entry<String, Long>> mostCommon = countByCity
.entrySet().stream()
.max(Map.Entry.comparingByValue());
mostCommon.ifPresent(e ->
System.out.println("Most common: " + e.getKey()
+ " (" + e.getValue() + " employees)"));
}
}
Most common: Mumbai (4 employees)
How do you handle ties?
long maxCount = countByCity.values().stream()
.mapToLong(Long::longValue).max().orElse(0);
List<String> tied = countByCity.entrySet().stream()
.filter(e -> e.getValue() == maxCount)
.map(Map.Entry::getKey)
.toList();
What are common mistakes?
Mistake: using distinct().count() to find the most common value.
// WRONG: distinct gives unique cities, not the most common
long uniqueCities = employees.stream()
.map(Employee::getCity)
.distinct()
.count();
// CORRECT: group and count, then max
What about finding the least common city?
Replace max with min:
Optional<Map.Entry<String, Long>> leastCommon = countByCity
.entrySet().stream()
.min(Map.Entry.comparingByValue());
How do you rank all cities by employee count?
countByCity.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue().reversed())
.forEach(e -> System.out.println(
e.getKey() + ": " + e.getValue()));
What about finding the most common value for any field?
The group-count-max pattern works for any field:
// Most common department
Optional<String> topDept = employees.stream()
.collect(Collectors.groupingBy(
Employee::getDepartment, Collectors.counting()))
.entrySet().stream()
.max(Map.Entry.comparingByValue())
.map(Map.Entry::getKey);
What about finding the top N most common cities?
List<String> topThree = countByCity.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue().reversed())
.limit(3)
.map(Map.Entry::getKey)
.toList();
System.out.println("Top 3 cities: " + topThree);
What are the edge cases?
If no employees exist, the map is empty and max returns Optional.empty(). If all employees share the same city, that city is the sole entry.
What should a senior engineer know?
At National Bank of India, Rajesh uses this pattern in the HR analytics dashboard to decide where to open new branch offices. The query runs on 50,000+ employee records. For large datasets, the groupingBy collector builds a HashMap internally, so the time complexity is O(n) for grouping and O(k) for finding the max, where k is the number of unique cities.
// Production pattern: find the city with the most employees
// and the average salary in that city for branch planning
String topCity = employees.stream()
.collect(Collectors.groupingBy(Employee::getCity, Collectors.counting()))
.entrySet().stream()
.max(Map.Entry.comparingByValue())
.map(Map.Entry::getKey)
.orElse("N/A");
BigDecimal avgSalary = employees.stream()
.filter(e -> e.getCity().equals(topCity))
.map(Employee::getSalary)
.reduce(BigDecimal.ZERO, BigDecimal::add)
.divide(BigDecimal.valueOf(
employees.stream().filter(e -> e.getCity().equals(topCity)).count()),
2, java.math.RoundingMode.HALF_UP);
For parallel streams, use groupingByConcurrent which returns a ConcurrentHashMap and avoids the merge step.
What are common interview follow-up questions?
- "How do you find the least common city?" Replace max with min.
- "How do you find the most common department in each city?" Nest groupingBy(city, groupingBy(dept, counting())), then find max within each city.
Visual Overview
groupingBy(city, counting()) ┌──────────────────────────┐ │ Mumbai → 4 │ ← max │ Delhi → 3 │ │ Chennai → 2 │ │ Pune → 1 │ └──────────────────────────┘ max(comparingByValue()) → Mumbai (4)
Key Takeaway
Finding the most common city uses the familiar group-then-max pattern: groupingBy(getCity, counting()) produces a frequency map, then max(comparingByValue()) on the entrySet finds the city with the highest count. The same pattern works for any 'most common X' question.
Remember one sentence: group by the field, count, then max by value to find the most common value of any field.
---