Definition
- Nested groupingBy produces
Mapof dept to gender to count.> - Ratio =
maleCount / femaleCountper department. - Division by zero: handle departments with zero females using
getOrDefault("F", 0L)with a guard. - Alternative: use partitioningBy(isMale, counting()) as the inner downstream.
The diversity team at the bank asks: 'For each department, what is the ratio of male to female employees?' Count males and females per department, then divide.
Understanding the Concepts
How do you compute the male-to-female ratio per department?
package com.bank.hr;
import java.util.*;
import java.util.stream.Collectors;
public class GenderRatioPerDept {
public static void main(String[] args) {
List<Employee> employees = Employee.getSampleEmployees();
Map<String, Map<String, Long>> deptGender = employees.stream()
.collect(Collectors.groupingBy(
Employee::getDepartment,
Collectors.groupingBy(
Employee::getGender,
Collectors.counting())));
deptGender.forEach((dept, genderMap) -> {
long male = genderMap.getOrDefault("M", 0L);
long female = genderMap.getOrDefault("F", 0L);
String ratio = female > 0
? String.format("%.2f:1", (double) male / female)
: male + ":0 (no females)";
System.out.printf("%s: M=%d, F=%d, ratio=%s%n",
dept, male, female, ratio);
});
}
}
TRADING: M=2, F=1, ratio=2.00:1
RISK: M=1, F=2, ratio=0.50:1
OPERATIONS: M=1, F=1, ratio=1.00:1
COMPLIANCE: M=1, F=1, ratio=1.00:1
What are common mistakes?
Mistake: not handling division by zero.
// WRONG: ArithmeticException if no females
double ratio = (double) male / female; // female = 0 → Infinity
// CORRECT: guard against zero
String safe = female > 0
? String.format("%.2f:1", (double) male / female)
: "all male";
What about using partitioningBy for the inner split?
Map<String, Map<Boolean, Long>> deptParity = employees.stream()
.collect(Collectors.groupingBy(
Employee::getDepartment,
Collectors.partitioningBy(
e -> "M".equals(e.getGender()),
Collectors.counting())));
// partitioningBy guarantees both true and false keys
partitioningBy as the inner downstream guarantees both male (true) and female (false) keys exist, eliminating the need for getOrDefault.
What about displaying as a percentage?
deptGender.forEach((dept, genderMap) -> {
long male = genderMap.getOrDefault("M", 0L);
long female = genderMap.getOrDefault("F", 0L);
long total = male + female;
System.out.printf("%s: Male %.0f%%, Female %.0f%%%n",
dept,
(double) male / total * 100,
(double) female / total * 100);
});
What about flagging departments with gender imbalance?
deptGender.forEach((dept, genderMap) -> {
long male = genderMap.getOrDefault("M", 0L);
long female = genderMap.getOrDefault("F", 0L);
long total = male + female;
double malePercent = (double) male / total * 100;
if (malePercent > 70 || malePercent < 30) {
System.out.println("IMBALANCE: " + dept
+ " (" + malePercent + "% male)");
}
});
What are the edge cases?
A department with zero employees would not appear in the result. A department with only male or only female employees would have a 0 in the other bucket (via getOrDefault), requiring the division-by-zero guard.
What are common interview follow-up questions?
- "How do you flag departments with gender imbalance above 70%?" Compute percentage, then filter.
- "How do you return the ratio as a record?" Create a
record GenderRatio(String dept, long male, long female, double ratio)and map to it.
Visual Overview
groupingBy(dept, groupingBy(gender, counting()))
TRADING ──→ { M: 2, F: 1 } → ratio 2.00:1
RISK ─────→ { M: 1, F: 2 } → ratio 0.50:1
OPS ──────→ { M: 1, F: 1 } → ratio 1.00:1
COMP ─────→ { M: 1, F: 1 } → ratio 1.00:1
Key Takeaway
Computing the gender ratio per department uses nested groupingBy(dept, groupingBy(gender, counting())) to get male and female counts per department, then divides male by female with a zero guard.
Remember one sentence: nest groupingBy twice for per-department per-gender counts, then compute the ratio with a division-by-zero guard.
---