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
- Create Map.
- Traverse strings.
- Calculate length.
- 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:
- Convert to character array.
- Sort characters.
- 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:
- Identify the grouping criteria.
- Use
Collectors.groupingBy(). - Provide classifier function.
- Add downstream collectors if needed.
- 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.