Group Strings by Length

Java coding interview problem for Java 8 Streams: Group Strings by Length.

Grouping elements based on a specific property is one of the most common Java Stream API interview problems.

A common example:

Group strings based on their length.

This problem introduces important concepts:

  • Stream API
  • Collectors.groupingBy()
  • Classifier functions
  • Lambda expressions
  • Map-based grouping
  • Data aggregation

What is String Grouping?

Grouping means collecting elements that share the same characteristic into a single group.


Example:

Input:

["Java","Spring","AI","Cloud"]

String lengths:

Java   → 4

Spring → 6

AI     → 2

Cloud  → 5

Grouped Result:

2 → [AI]

4 → [Java]

5 → [Cloud]

6 → [Spring]

Understanding Grouping Problems

Many real-world problems follow this pattern:

Collection

      ↓

Find Common Property

      ↓

Create Groups

      ↓

Store Result

Examples:

Employees

Group by:

Department

Result:

IT → Employees

HR → Employees

Products

Group by:

Category

Result:

Electronics → Products

Books → Products

Transactions

Group by:

Transaction Type

Result:

Credit → Transactions

Debit → Transactions

Why Group Strings by Length?

This simple problem teaches concepts used in complex applications.

It helps understand:

  • Classification
  • Data aggregation
  • Map creation
  • Collector operations

Difference Between Grouping and Partitioning

Both look similar but solve different problems.


Partitioning

Creates exactly two groups.

Example:

Even

Odd

Using:

partitioningBy()

Grouping

Creates multiple groups.

Example:

Length 2

Length 4

Length 6

Using:

groupingBy()

Comparison

Feature Grouping Partitioning
Groups Multiple Exactly two
Method groupingBy() partitioningBy()
Key Any value Boolean
Example String length Even/Odd

Real-World Applications

Search Systems

Group words by:

Length

Category

Prefix

Text Analytics

Analyze:

Word sizes

Frequency

Patterns

Auto Complete Systems

Group suggestions by:

Word length

Data Processing

Organize records by:

Common attributes

Problem Statement

Given a list of strings, group strings based on their length using Java Streams.


Input Example

[
"Java",
"AI",
"Spring",
"Go",
"Cloud"
]

Expected Output

{
2=[AI,Go],

4=[Java],

5=[Cloud],

6=[Spring]
}

Java Stream API Overview

Java Streams provide a functional approach to processing collections.


Stream flow:

Collection

    ↓

Stream

    ↓

Transformation

    ↓

Collector

    ↓

Result

Example:

list.stream()

.collect()

Stream Pipeline Concept

A Stream pipeline contains:

Source

 ↓

Intermediate Operations

 ↓

Terminal Operation

Example:

strings.stream()

.collect(

Collectors.groupingBy()

);

Flow:

List<String>

      ↓

stream()

      ↓

Find String Length

      ↓

Create Groups

      ↓

Map<Integer,List<String>>

Collectors.groupingBy() Introduction

groupingBy() groups stream elements based on a classifier function.


Syntax:

Collectors.groupingBy(
    classifier
)

The classifier decides:

Which group does this element belong to?

Example:

Collectors.groupingBy(
    String::length
)

Meaning:

String length becomes Map key

Result Type

For:

String::length

the result is:

Map<Integer,List<String>>

Example:

4 → [Java]

6 → [Spring]

Approach 1 — Traditional Loop Approach

Before Streams, developers used loops and HashMap.


Algorithm

  1. Create Map.
  2. Traverse strings.
  3. Calculate length.
  4. Add string to corresponding list.

Java Program

import java.util.*;

public class GroupStringsByLength {


    public static Map<Integer,List<String>>
    groupByLength(List<String> strings) {


        Map<Integer,List<String>> result =
                new HashMap<>();


        for(String word : strings) {


            int length = word.length();


            result
            .computeIfAbsent(
                length,
                key -> new ArrayList<>()
            )
            .add(word);

        }


        return result;

    }


    public static void main(String[] args) {


        List<String> words =
                Arrays.asList(
                    "Java",
                    "AI",
                    "Spring",
                    "Go"
                );


        System.out.println(
            groupByLength(words)
        );

    }

}

Output

{
2=[AI,Go],

4=[Java],

6=[Spring]
}

Step-by-Step Explanation

Input:

Java

AI

Spring

Go

Initial Map:

{}

Process:

Java

Length:

4

Add:

4 → [Java]

AI

Length:

2

Add:

2 → [AI]

Spring

Length:

6

Add:

6 → [Spring]

Go

Length:

2

Existing group:

2 → [AI]

Add:

2 → [AI,Go]

Final:

2 → [AI,Go]

4 → [Java]

6 → [Spring]

Approach 2 — Using Streams and groupingBy()

Java provides a cleaner solution.


Java Program

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


public class GroupStringsUsingStreams {


    public static Map<Integer,List<String>>
    groupByLength(List<String> strings) {


        return strings.stream()

                .collect(

                    Collectors.groupingBy(
                        String::length
                    )

                );

    }


    public static void main(String[] args) {


        List<String> words =
                Arrays.asList(
                    "Java",
                    "AI",
                    "Spring",
                    "Go"
                );


        System.out.println(
            groupByLength(words)
        );

    }

}

Output

{
2=[AI,Go],

4=[Java],

6=[Spring]
}

Step-by-Step Stream Explanation

Input:

Java

AI

Spring

Go

Stream:

Java

AI

Spring

Go

Classifier:

String::length

Evaluation:

Java → 4

AI → 2

Spring → 6

Go → 2

Groups:

2 → AI,Go

4 → Java

6 → Spring

Stream Pipeline Diagram

List<String>

      ↓

stream()

      ↓

String::length

      ↓

groupingBy()

      ↓

Map<Integer,List<String>>

Handling Empty Strings

Example:

Input:

["Java","","AI"]

Length:

Java → 4

"" → 0

AI → 2

Output:

0 → [""]

2 → ["AI"]

4 → ["Java"]

Handling Null Values

Input:

["Java",null,"AI"]

Problem:

String::length

cannot process null.


Solution:

Filter null values:

strings.stream()

.filter(
    Objects::nonNull
)

.collect(

Collectors.groupingBy(
    String::length
)

);

Sorting Groups

Default:

HashMap

does not guarantee order.


To sort keys:

strings.stream()

.collect(

Collectors.groupingBy(

String::length,

TreeMap::new,

Collectors.toList()

)

);

Result:

2 → [AI]

4 → [Java]

6 → [Spring]

Complexity Analysis

Let:

n = number of strings

Traversal:

O(n)

Length calculation:

O(1)

Total:

O(n)

Space:

O(n)

because all elements are stored in groups.


Advantages

  • Clean and readable.
  • Uses functional programming.
  • Easy to extend.
  • Works for any classifier.

Drawbacks

  • Requires Stream knowledge.
  • Additional memory for groups.
  • Complex grouping may reduce readability.

Deep Dive Into Collectors.groupingBy()

Collectors.groupingBy() is one of the most powerful collectors in Java Stream API.

It converts:

Stream<T>

      ↓

Map<K,List<T>>

How groupingBy() Works Internally

The grouping process:

Element

    ↓

Classifier Function

    ↓

Generate Key

    ↓

Add Element To Group

Example:

Input:

["Java","AI","Spring"]

Classifier:

String::length

Processing:

Java → 4

AI → 2

Spring → 6

Generated Map:

4 → [Java]

2 → [AI]

6 → [Spring]

Understanding Classifier Function

The classifier decides:

Which group does this element belong to?


Example:

Collectors.groupingBy(
    String::length
)

Classifier:

String

      ↓

length

      ↓

Integer Key

Other examples:

First Character

word -> word.charAt(0)

Department

Employee::getDepartment

Salary Range

employee -> employee.getSalary() > 100000

Group Strings by First Character

Problem:

Group words based on their first letter.


Input:

["Java","Spring","Python","JavaScript"]

Expected:

J → [Java,JavaScript]

S → [Spring]

P → [Python]

Java Program

Map<Character,List<String>> result =

words.stream()

.collect(

Collectors.groupingBy(

word -> word.charAt(0)

)

);

Dry Run

Input:

Java
Spring
Python
JavaScript

Process:

Java → J

Spring → S

Python → P

JavaScript → J

Result:

J → [Java,JavaScript]

S → [Spring]

P → [Python]

Group Strings by Last Character

Example:

Input:

["Java","Scala","Python","Go"]

Last character:

Java → a

Scala → a

Python → n

Go → o

Code:

Map<Character,List<String>> result =

words.stream()

.collect(

Collectors.groupingBy(

word ->
word.charAt(
word.length()-1
)

)

);

Output:

a → [Java,Scala]

n → [Python]

o → [Go]

Group Strings by Anagram Pattern

Very common interview problem.

Problem:

Group words that are anagrams.


Input:

["eat","tea","tan","ate","nat"]

Expected:

[aet] → [eat,tea,ate]

[ant] → [tan,nat]

Approach

For every word:

  1. Convert to character array.
  2. Sort characters.
  3. Use sorted value as key.

Example:

eat

↓

aet

tea

↓

aet

Same key:

aet

Java Program

Map<String,List<String>> result =

words.stream()

.collect(

Collectors.groupingBy(

word -> {

char[] chars =
        word.toCharArray();


Arrays.sort(chars);


return new String(chars);

}

)

);

Nested Grouping Examples

Sometimes applications require multiple grouping levels.

Example:

Employee:

Department

+

Salary Range

First:

Department

Second:

Salary Category

Java Program

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

employees.stream()

.collect(

Collectors.groupingBy(

Employee::getDepartment,

Collectors.groupingBy(

employee ->
employee.getSalary() > 100000
?
"High"
:
"Low"

)

)

);

Result:

IT

   High → Employees

   Low  → Employees


HR

   High → Employees

Counting Strings by Length

Sometimes we only need counts.

Example:

Input:

["AI","Go","Java","Spring"]

Result:

2 → 2

4 → 1

6 → 1

Java Program

Map<Integer,Long> result =

words.stream()

.collect(

Collectors.groupingBy(

String::length,

Collectors.counting()

)

);

Understanding counting()

Collector:

Collectors.counting()

returns:

Long count

Example:

Group:

Java

Go

AI

Count:

3

Sorting Groups by Size

Example:

Input:

["a","bb","cc","ddd"]

Group:

1 → [a]

2 → [bb,cc]

3 → [ddd]

Sort groups by number of elements.


Code:

Map<Integer,List<String>> grouped =

words.stream()

.collect(

Collectors.groupingBy(
    String::length
)

);


grouped.entrySet()

.stream()

.sorted(

Comparator.comparing(
    entry ->
    entry.getValue().size()
)

.reversed()

)

.toList();

Converting Grouped Result to Map

Example:

Grouped result:

Map<Integer,List<String>>

Convert to another format:

Map<Integer,Integer> countMap =

grouped.entrySet()

.stream()

.collect(

Collectors.toMap(

Map.Entry::getKey,

entry ->
entry.getValue().size()

)

);

Result:

Length → Count

Example:

2 → 3

4 → 1

groupingBy() vs partitioningBy()

Both are collectors.


groupingBy()

Used for:

Multiple categories

Example:

Length:

2

4

6

Returns:

Map<K,List<T>>

partitioningBy()

Used for:

Two categories

Example:

Valid

Invalid

Returns:

Map<Boolean,List<T>>

Comparison Table

Feature groupingBy() partitioningBy()
Groups Multiple Two
Key Any Type Boolean
Function Classifier Predicate
Example Length Even/Odd

Stream vs Loop Comparison

Feature Loop Stream
Code Verbose Compact
Readability Good Excellent
Parallel support Manual Built-in
Functional style No Yes
Complex grouping More code Cleaner

HashMap Internal Working

groupingBy() normally creates:

HashMap

When grouping:

Key

 ↓

hashCode()

 ↓

Bucket

 ↓

Store List

Example:

4 → [Java,Code]

HashMap stores:

Key = 4

Value = List<String>

Parallel Stream Considerations

For large datasets:

parallelStream()

can be used.

Example:

words.parallelStream()

.collect(

Collectors.groupingByConcurrent(
    String::length
)

);

Benefits:

  • Parallel grouping
  • Better performance for large data

Consider:

  • Ordering
  • Thread overhead
  • Data size

Common Interview Mistakes

Mistake 1

Using groupingBy for two groups.

Example:

Even/Odd

Better:

partitioningBy()

Mistake 2

Forgetting duplicate values.

Grouping automatically handles duplicates.


Mistake 3

Using wrong classifier.

Example:

Wrong:

word -> word.length()

when requirement is:

First character

Mistake 4

Ignoring null values.

Example:

["Java",null]

Solution:

.filter(
Objects::nonNull
)

Edge Cases

Case Handling
Empty list Returns empty map
Null strings Filter null values
Duplicate strings Automatically grouped
Single element Creates one group
Large data Consider parallel grouping

Interview Follow-up Questions

Q1. Explain groupingBy() internally.

Q2. Difference between groupingBy() and partitioningBy().

Q3. Group employees by department.

Q4. Count elements in each group.

Q5. Group anagrams using Streams.

Q6. How to sort grouped results?

Q7. How does HashMap store grouped data?


Related Java Collection Problems

  • Partition Even and Odd Numbers
  • Convert List to Map Using Streams
  • Character Frequency Using Streams
  • Find Duplicate Elements Using Streams
  • Group Employees by Department
  • Sort Map by Value
  • Custom Comparator Examples

Key Takeaways

Grouping pattern:

Collection

      ↓

Classifier Function

      ↓

Create Key

      ↓

Collect Elements

      ↓

Map<K,List<V>>

Use:

Multiple groups

Collectors.groupingBy()

Use:

Counting groups

Collectors.counting()

Use:

Nested reports

groupingBy(
    groupingBy()
)

Use:

Two groups

partitioningBy()

Complexity:

Time:

O(n)

Space:

O(n)

Frequently Asked Interview Questions

Q1. What does groupingBy() return?

A:

Map<K,List<T>>

Q2. Can groupingBy() count elements?

A:

Yes, using:

Collectors.counting()

Q3. Can we group custom objects?

A:

Yes, using any classifier method.


Q4. What is the difference between groupingBy() and toMap()?

A:

toMap() creates one value per key.

groupingBy() stores multiple values per key.


Interview Tip

When asked:

"Group strings using Java Streams."

Explain:

  1. Identify the grouping criteria.
  2. Use Collectors.groupingBy().
  3. Provide classifier function.
  4. Add downstream collectors if needed.
  5. Discuss complexity and null handling.

For senior Java interviews, discuss:

  • Collector design.
  • HashMap internals.
  • Nested grouping.
  • Concurrent collectors.
  • Stream performance.

This demonstrates strong understanding of Java Streams, Collections, and data aggregation patterns.