Back to Stream: map & Transform
Q20Question 20 of 34

Convert a Map<String, List<Employee>> to Map<String, Long> (department to count)

Key Concepts
  • Stream entrySet, then toMap(Entry::getKey, e -> (long) e.getValue().size()) replaces lists with counts
  • Casting size() to long keeps the type consistent with counting()-based results elsewhere
  • Converting an existing grouped map is cheaper than regrouping from the raw employee list
  • If starting from raw employees, use groupingBy(dept, counting()) directly instead
  • Source keys are unique, so no merge function is needed in toMap
  • The source map is unchanged; the stream produces a new lightweight map

Definition

Stream entrySet and collect with toMap, keeping the key and replacing each list value with its size cast to Long.
  • entrySet().stream() iterates the existing grouped map.
  • toMap(Entry::getKey, e -> (long) e.getValue().size()) keeps the department and replaces the list with its count.
  • Cast to long aligns the type with counting()-based results.
  • No merge function needed because the source keys are unique.
  • Converting an existing map is cheaper than regrouping from scratch.

Priya at the National Bank of India already has a chart of which employees are in each department. She wants a slimmer chart that just shows how many are in each, so she replaces each name list with its count.

Understanding the Concepts

How do you convert a grouped map to a count map?

Stream the entrySet, keep the key, and replace each list with its size.

JAVA
package com.bank.hr;

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

public class GroupedMapToCount {
    public static void main(String[] args) {
        Map<String, List<Employee>> grouped = Map.of(
            "Loans",   List.of(new Employee("Rajesh"), new Employee("Amit")),
            "IT",      List.of(new Employee("Priya"), new Employee("Kavita"), new Employee("Neha")),
            "Finance", List.of(new Employee("Suresh"))
        );

        Map<String, Long> counts = grouped.entrySet().stream()
            .collect(Collectors.toMap(
                Map.Entry::getKey,
                e -> (long) e.getValue().size()));

        counts.forEach((dept, count) ->
            System.out.println(dept + ": " + count));
    }
}
TEXT
Loans: 2
IT: 3
Finance: 1

When should you convert vs regroup?

| Scenario | Approach |
|---|---|
| Already have the grouped map | Convert with entrySet().stream().toMap |
| Starting from raw employee list | Use groupingBy(dept, counting()) directly |

JAVA
// Direct from raw employees (no intermediate grouped map)
Map<String, Long> directCounts = employees.stream()
    .collect(Collectors.groupingBy(
        Employee::getDepartment,
        Collectors.counting()));

What are common mistakes?

Mistake: forgetting to cast size() to long.

JAVA
// size() returns int; if the rest of the system uses Long counts, this mismatch causes issues
Map<String, Integer> intCounts = grouped.entrySet().stream()
    .collect(Collectors.toMap(
        Map.Entry::getKey,
        e -> e.getValue().size()));  // Integer, not Long

// Consistent with counting(): cast to long
Map<String, Long> longCounts = grouped.entrySet().stream()
    .collect(Collectors.toMap(
        Map.Entry::getKey,
        e -> (long) e.getValue().size()));

What should a senior engineer know?

  • Recognise where the grouped map came from. Converting is useful when the map was built for another purpose and a summary is needed as a secondary output.
  • The conversion produces a far lighter payload for API responses or dashboards.
  • Source keys are unique, so no merge function is needed.
  • If you need both the grouped map and the counts, compute the counts from the existing map rather than streaming the raw data again.

What about filtering the resulting count map?

After converting, filter departments exceeding a threshold.

JAVA
Map<String, Long> largeDepts = counts.entrySet().stream()
    .filter(e -> e.getValue() > 2)
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

What about empty lists in the source map?

If a department key maps to an empty list, size() returns 0 and the count map contains a zero entry. Filter these if departments with no employees should not appear.

JAVA
Map<String, Long> nonEmpty = counts.entrySet().stream()
    .filter(e -> e.getValue() > 0)
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

What about converting to average salary instead of count?

JAVA
Map<String, Double> avgSalary = grouped.entrySet().stream()
    .collect(Collectors.toMap(
        Map.Entry::getKey,
        e -> e.getValue().stream()
            .map(Employee::getSalary)
            .mapToDouble(java.math.BigDecimal::doubleValue)
            .average().orElse(0.0)));

What are common interview follow-up questions?

  • "How do you convert a grouped map to Map of average salary?" Replace size with averaging logic using each list.
  • "How do you filter departments with count > 2?" Chain a filter after streaming the converted map.
  • "Can you do this in one pass from the original employees?" Yes, with groupingBy(dept, counting()).

Visual Overview

DIAGRAM
  Map<String, List<Employee>>
  ┌───────────────────────────────────────┐
  │  Loans   → [Rajesh, Amit]      (2)   │
  │  IT      → [Priya, Kavita, Neha] (3) │
  │  Finance → [Suresh]            (1)   │
  └───────────────────────────────────────┘
       │
       │  entrySet().stream()
       │  toMap(key, list.size())
       ▼
  Map<String, Long>
  ┌──────────────────┐
  │  Loans   → 2     │
  │  IT      → 3     │
  │  Finance → 1     │
  └──────────────────┘

Key Takeaway

When you already hold a grouped map and only need the head count per group, convert it by streaming the entrySet and collecting with toMap, replacing each list with its size cast to Long. This produces a lightweight count map without regrouping from scratch.

At the National Bank of India, a detail API had already built the department-to-employees map, and a summary endpoint needed just the counts. Converting the existing map is cheaper than re-streaming the raw data.

If starting from the raw employee list, skip the conversion and use groupingBy(dept, counting()) directly. Cast size() to long to keep the type consistent with counting()-based results elsewhere in the system.

Remember one sentence: stream the entrySet of a grouped map and toMap(key, list.size()) to convert a grouped map into a count map without regrouping.

---

Share
Use ← → arrow keys to navigate