Group Employees by Department

Java coding interview problem for Collections: Group Employees by Department.

Grouping objects is one of the most common problems in Java Collections interviews.

The problem teaches an important data processing pattern:

Collection of Objects

        ↓

Choose Grouping Criteria

        ↓

Create Groups

        ↓

Process Grouped Data

In real applications, data is rarely stored as a simple list.

Usually, we need to organize data based on:

  • Department
  • Location
  • Category
  • Type
  • Status
  • Date

What is Grouping Objects?

Grouping means collecting objects that share a common attribute.

Example:

Employee list:

John      IT

Alice     HR

Bob       IT

David     Finance

Group by department:

IT

    John

    Bob


HR

    Alice


Finance

    David

Understanding Employee Grouping Concept

An employee object contains multiple properties:

Employee

 |
 |-- id
 |
 |-- name
 |
 |-- department
 |
 |-- salary

We select one property as the grouping key.

Example:

department

becomes:

Map Key

Employees become:

Map Value

Map Structure for Grouping

Grouping uses:

Map<Key, List<Value>>

Example:

Department → Employees

Data structure:

HashMap

    |

    +---- IT
    |       |
    |       + John
    |       + Bob
    |
    |
    +---- HR
    |       |
    |       + Alice

Key-Value Relationship

Input:

Employee(
101,
John,
IT
)

Stored as:

IT

 ↓

[
 John
]

Another employee:

Employee(
102,
Bob,
IT
)

Updated:

IT

 ↓

[
 John,
 Bob
]

Why HashMap is Used for Grouping?

HashMap provides:

Fast Lookup

Average:

O(1)

When adding an employee:

Check:

Does department exist?

If yes:

Add employee to existing list

If no:

Create new list

Real-World Applications

Employee Management Systems

Group employees by:

  • Department
  • Location
  • Team

Example:

Engineering

Sales

HR

Banking Applications

Group:

Customers

↓

Account Type

Example:

Savings

Checking

Business

E-Commerce Systems

Group products by:

  • Category
  • Brand
  • Price range

Data Analytics

Group events by:

  • Date
  • Region
  • User type

Problem Statement

Given a list of employees, group employees based on their department.


Employee Class Design

Employee fields:

id

name

department

salary

Employee Class

class Employee {


    private int id;


    private String name;


    private String department;


    private double salary;


    public Employee(
            int id,
            String name,
            String department,
            double salary) {


        this.id = id;

        this.name = name;

        this.department = department;

        this.salary = salary;

    }


    public String getDepartment() {

        return department;

    }


    public String getName() {

        return name;

    }


    public double getSalary() {

        return salary;

    }


    @Override
    public String toString() {


        return name +
                " - " +
                department +
                " - " +
                salary;

    }

}

Input Example

Employees:

[
John IT 90000,

Alice HR 70000,

Bob IT 95000,

David Finance 80000
]

Expected Output

IT

 [
  John,
  Bob
 ]


HR

 [
  Alice
 ]


Finance

 [
  David
 ]

Grouping Visualization

Input:

John      IT

Alice     HR

Bob       IT

David     HR

Initial:

{}

Read:

John IT

Map:

IT → [John]

Read:

Alice HR

Map:

IT → [John]

HR → [Alice]

Read:

Bob IT

Map:

IT → [John,Bob]

HR → [Alice]

Read:

David HR

Final:

IT → [John,Bob]

HR → [Alice,David]

HashMap Internal Working

When grouping:

map.put(department, employeeList);

Java performs:

Department

       ↓

hashCode()

       ↓

Bucket

       ↓

Store List

Example:

IT

hashCode()

Bucket 5

Approach 1 — Manual Grouping Using Loops

The basic approach:

  1. Create HashMap.
  2. Traverse employees.
  3. Check department.
  4. Add employee.

Algorithm

For every employee:

Get department

       ↓

Check existing group

       ↓

Create or add

Java Program — Manual Grouping

import java.util.*;

public class GroupEmployeesManual {


    public static Map<String,List<Employee>>
    groupEmployees(
            List<Employee> employees) {


        Map<String,List<Employee>> map =
                new HashMap<>();


        for(Employee employee :
                employees) {


            String department =
                    employee.getDepartment();


            if(!map.containsKey(department)) {


                map.put(
                    department,
                    new ArrayList<>()
                );

            }


            map.get(department)
               .add(employee);

        }


        return map;

    }

}

Step-by-Step Explanation

Input:

John IT

Alice HR

Bob IT

Start:

{}

Process John:

Department:

IT

Create:

IT → [John]

Process Alice:

Department:

HR

Create:

HR → [Alice]

Process Bob:

Department:

IT

Existing group found.

Add:

IT → [John,Bob]

Using computeIfAbsent()

Java provides a cleaner approach.

Instead of:

if(!map.containsKey(key))

use:

map.computeIfAbsent()

Java Program

public static Map<String,List<Employee>>
groupEmployees(
        List<Employee> employees) {


    Map<String,List<Employee>> map =
            new HashMap<>();


    for(Employee employee :
            employees) {


        map.computeIfAbsent(
                employee.getDepartment(),
                key -> new ArrayList<>()
        )
        .add(employee);

    }


    return map;

}

How computeIfAbsent Works

Example:

Department:

IT

First employee:

IT does not exist

Create:

IT → new ArrayList()

Add employee.


Second employee:

IT exists

Use existing list.

Add employee.


Complexity Analysis

For:

n employees

Each employee is processed once.

Time:

O(n)

Space:

O(n)

because all employees are stored in groups.


Advantages

  • Simple.
  • Efficient.
  • Uses standard Java collections.
  • Easy to extend.

Drawbacks

  • More boilerplate code.
  • Manual list creation.
  • Requires HashMap handling.

Approach 2 — Java 8 Stream groupingBy()

Java 8 introduced a powerful Collector:

Collectors.groupingBy()

It simplifies object grouping operations.


groupingBy() Concept

The pattern:

Collection

    ↓

Stream

    ↓

groupingBy()

    ↓

Map<Key,List<Value>>

Basic Syntax

Collectors.groupingBy(
        Employee::getDepartment
)

This creates:

Map<String,List<Employee>>

where:

Key = Department

Value = Employees

Java Program — Group Employees by Department

import java.util.*;
import java.util.stream.Collectors;


public class GroupEmployeesUsingStreams {


    public static Map<String,List<Employee>>
    groupEmployees(
            List<Employee> employees) {


        return employees.stream()

                .collect(
                    Collectors.groupingBy(
                        Employee::getDepartment
                    )
                );

    }

}

Output Example

Input:

John      IT

Alice     HR

Bob       IT

David     Finance

Output:

IT

[
 John,
 Bob
]


HR

[
 Alice
]


Finance

[
 David
]

Step-by-Step Execution

Input:

[
John IT,

Alice HR,

Bob IT
]

Create Stream:

John IT

Alice HR

Bob IT

Grouping Key:

Employee::getDepartment

First Employee:

Department = IT

Create:

IT → [John]

Second Employee:

Department = HR

Create:

HR → [Alice]

Third Employee:

Department = IT

Existing group:

IT → [John]

Add:

IT → [John,Bob]

Group Employees by Department Count

A common interview question:

How many employees are in each department?


Expected:

IT → 2

HR → 1

Finance → 1

Using counting()

Map<String,Long> countByDepartment =
        employees.stream()

        .collect(
            Collectors.groupingBy(
                Employee::getDepartment,
                Collectors.counting()
            )
        );

Output

IT = 2

HR = 1

Finance = 1

Find Highest Salary Employee Per Department

Another common variation:

Find the highest paid employee in each department.


Example:

Input:

John IT 90000

Bob IT 120000

Alice HR 80000

Output:

IT → Bob

HR → Alice

Java Program

Map<String,Optional<Employee>>
highestSalary =
        employees.stream()

        .collect(
            Collectors.groupingBy(
                Employee::getDepartment,

                Collectors.maxBy(
                    Comparator.comparing(
                        Employee::getSalary
                    )
                )
            )
        );

Explanation

Grouping:

Department

Then:

Find maximum salary

inside each group.


Average Salary Per Department

Example:

IT

Average salary = 100000

Using averagingDouble()

Map<String,Double> averageSalary =
        employees.stream()

        .collect(
            Collectors.groupingBy(
                Employee::getDepartment,

                Collectors.averagingDouble(
                    Employee::getSalary
                )
            )
        );

Output

IT = 105000

HR = 80000

Grouping By Multiple Criteria

Real applications often require multiple grouping levels.

Example:

Department

        +

Location

Employee data:

John

IT

Texas


Alice

IT

California

Result:

IT

 |
 |
 + Texas
 |
 + California

Nested groupingBy()

Map<String,
    Map<String,List<Employee>>>
result =

employees.stream()

.collect(

Collectors.groupingBy(
    Employee::getDepartment,

    Collectors.groupingBy(
        Employee::getLocation
    )
)

);

Multiple Grouping Example

Input:

John IT Texas

Bob IT Texas

Alice HR California

Output:

IT

  Texas

     John

     Bob


HR

  California

     Alice

Group Employees By Salary Range

Example:

Salary categories:

LOW

MEDIUM

HIGH

Use custom classifier:

employees.stream()

.collect(
    Collectors.groupingBy(
        employee -> {

            if(employee.getSalary() < 50000)
                return "LOW";

            else if(employee.getSalary() < 100000)
                return "MEDIUM";

            else
                return "HIGH";

        }
    )
);

Grouping With LinkedHashMap

Default:

HashMap

does not guarantee order.


If insertion order is required:

Collectors.groupingBy(
    Employee::getDepartment,
    LinkedHashMap::new,
    Collectors.toList()
)

Grouping With TreeMap

If sorted department names are required:

Collectors.groupingBy(
    Employee::getDepartment,
    TreeMap::new,
    Collectors.toList()
)

HashMap vs LinkedHashMap vs TreeMap

Feature HashMap LinkedHashMap TreeMap
Order No guarantee Insertion order Sorted order
Performance O(1) O(1) O(log n)
Grouping Default Yes Optional Optional
Use Case Fast grouping Ordered reports Sorted reports

Collectors API Deep Dive

Common collectors:

toList()

Collect elements:

Collectors.toList()

counting()

Count elements:

Collectors.counting()

averagingDouble()

Calculate average:

Collectors.averagingDouble()

maxBy()

Find maximum:

Collectors.maxBy()

minBy()

Find minimum:

Collectors.minBy()

mapping()

Transform grouped values.

Example:

Group employee names:

Collectors.groupingBy(
    Employee::getDepartment,

    Collectors.mapping(
        Employee::getName,
        Collectors.toList()
    )
)

Custom Object Grouping

Grouping is not limited to Employee.

Example:

Product:

id

name

category

Group:

category → products

Example:

Map<String,List<Product>> products =
        list.stream()

        .collect(
            Collectors.groupingBy(
                Product::getCategory
            )
        );

Primitive vs Object Collections

Java Collections work with objects.

Cannot:

Map<int,List<int>>

Use:

Map<Integer,List<Integer>>

Autoboxing:

int

↓

Integer

Common Interview Mistakes

Mistake 1

Using loops unnecessarily.

Modern Java:

groupingBy()

is cleaner.


Mistake 2

Wrong grouping key.

Example:

Need:

department

but grouping by:

name

creates incorrect output.


Mistake 3

Ignoring order requirements.

Need sorted groups?

Use:

TreeMap

Mistake 4

Using groupingBy when only counting is required.

For counts:

counting()

is better.


Edge Cases

Case Handling
Empty employee list Return empty map
One department Single group
One employee One element list
Null department Handle separately
Large data Stream processing

Interview Follow-up Questions

Q1. Group employees by department.

Q2. Count employees in each department.

Q3. Find highest salary employee per department.

Q4. Find average salary by department.

Q5. Group employees by department and location.

Q6. Difference between groupingBy and partitioningBy.

Q7. Preserve order while grouping.

Q8. Sort employees inside each department.


Related Java Collection Problems

  • Count Word Frequency Using HashMap
  • Sort Employees by Salary
  • Remove Duplicate Objects
  • Find Duplicate Elements Using Set
  • Find Top K Frequent Elements
  • Group Anagrams
  • Partition Numbers Using Predicate

Key Takeaways

Employee grouping follows this pattern:

List<Employee>

        ↓

Choose Grouping Key

        ↓

Map<Key,List<Employee>>

        ↓

Process Groups

Recommended approaches:

Simple grouping

Use:

HashMap

Modern Java approach

Use:

Collectors.groupingBy()

Ordered grouping

Use:

LinkedHashMap

or

TreeMap

Complexity:

For:

n employees

Time:

O(n)

Space:

O(n)

Frequently Asked Interview Questions

Q1. What does groupingBy return?

A:

Map<K,List<T>>

Q2. What is the difference between groupingBy and partitioningBy?

groupingBy:

Multiple groups

partitioningBy:

Two groups (true/false)

Q3. How do you find highest salary employee per department?

Use:

groupingBy()

+

maxBy()

Q4. How do you maintain order while grouping?

Use:

LinkedHashMap

Interview Tip

When asked:

"Group employees by department in Java."

Explain:

  1. Choose grouping key.
  2. Use Map of department to employee list.
  3. Implement with HashMap or groupingBy().
  4. Discuss advanced operations:
    • Count employees.
    • Average salary.
    • Maximum salary.
    • Nested grouping.

For senior Java interviews, discuss:

  • HashMap internals.
  • Collectors API.
  • Stream processing.
  • Performance considerations.

This demonstrates strong understanding of Java Collections, Stream API, and enterprise data processing patterns.