How to Separate Even and Odd Elements into Two Arrays in Java
Once you know how to count even and odd elements, the next logical step is to separate them into two different arrays. This introduces an important limitation of Java arrays: since arrays have a fixed size, you don't know how large the even and odd arrays should be until you've examined every element. This guide explains the classic two-pass solution, an easier ArrayList approach, and a Java Streams alternative.
Problem Statement
Given an array like:
{10, 15, 22, 7, 8, 3}
Create two separate arrays:
Even array:
{10, 22, 8}
Odd array:
{15, 7, 3}
The Fixed-Size Array Challenge
Java arrays must be created with a known size.
Since you don't know beforehand how many even and odd elements exist, there are two common solutions:
- Count the even and odd elements first, then create arrays of the correct size.
- Use dynamically resizable collections such as
ArrayList, which automatically grow as elements are added.
Method 1: Two-Pass Counting Approach (Pure Arrays)
public class SeparateEvenOdd {
public static void main(String[] args) {
int[] numbers = {10, 15, 22, 7, 8, 3};
int evenCount = 0;
for (int num : numbers) {
if (num % 2 == 0) {
evenCount++;
}
}
int oddCount = numbers.length - evenCount;
int[] evenArray = new int[evenCount];
int[] oddArray = new int[oddCount];
int evenIndex = 0;
int oddIndex = 0;
for (int num : numbers) {
if (num % 2 == 0) {
evenArray[evenIndex++] = num;
} else {
oddArray[oddIndex++] = num;
}
}
System.out.println("Even: " +
java.util.Arrays.toString(evenArray));
System.out.println("Odd: " +
java.util.Arrays.toString(oddArray));
}
}
This solution makes two passes through the array:
- First pass counts the number of even elements.
- Second pass copies each value into the appropriate array.
Method 2: Using ArrayList
import java.util.ArrayList;
import java.util.List;
int[] numbers = {10, 15, 22, 7, 8, 3};
List<Integer> evenList = new ArrayList<>();
List<Integer> oddList = new ArrayList<>();
for (int num : numbers) {
if (num % 2 == 0) {
evenList.add(num);
} else {
oddList.add(num);
}
}
System.out.println("Even: " + evenList);
System.out.println("Odd: " + oddList);
Since ArrayList automatically resizes itself, only one pass through the array is needed.
This is the approach most commonly used in real-world Java applications.
Method 3: Java Streams
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
Map<Boolean, int[]> partitioned =
Arrays.stream(numbers)
.boxed()
.collect(Collectors.partitioningBy(
n -> n % 2 == 0,
Collectors.collectingAndThen(
Collectors.toList(),
list -> list.stream()
.mapToInt(Integer::intValue)
.toArray()
)
));
int[] evenArray = partitioned.get(true);
int[] oddArray = partitioned.get(false);
Collectors.partitioningBy() is designed specifically for dividing elements into two groups based on a boolean condition.
Step-by-Step Explanation
Two-Pass Array Method
The first loop counts the number of even elements.
The number of odd elements is calculated using:
oddCount = numbers.length - evenCount;
Two arrays are then created with exactly the required sizes.
The second loop copies each element into either the even array or the odd array using separate index variables.
ArrayList Method
Two empty ArrayList objects are created.
Each number is examined once.
Even numbers are added to one list, while odd numbers are added to the other.
Since ArrayList resizes automatically, no preliminary counting is required.
Internal Working (Memory View)
For the array:
{10, 15, 22, 7, 8, 3}
First Pass
Even elements = 3
Odd elements = 3
Allocate:
evenArray[3]
oddArray[3]
Second Pass
10 -> evenArray[0]
15 -> oddArray[0]
22 -> evenArray[1]
7 -> oddArray[1]
8 -> evenArray[2]
3 -> oddArray[2]
Final arrays:
evenArray = [10, 22, 8]
oddArray = [15, 7, 3]
Real-Life Analogy
Imagine sorting playing cards into two piles: red cards and black cards.
If someone gives you two boxes that must exactly fit the number of cards in each pile, you would first count how many red and black cards exist before choosing the correct box sizes.
Using an ArrayList is like using expandable baskets that automatically grow as you place cards inside.
Best Practices
- Use
ArrayListwhen the sizes of the output collections are unknown. - Use the two-pass primitive array approach when the final result must be an
int[]. - Convert
ArrayList<Integer>intoint[]usingstream().mapToInt(Integer::intValue).toArray()when needed. - Use
Collectors.partitioningBy()for concise stream-based solutions.
Common Mistakes
- Trying to create both arrays in a single pass without knowing their required sizes.
- Forgetting to maintain separate indices for the even and odd arrays.
- Attempting to create
ArrayList<int>, which is invalid because Java generics work only with objects. - Forgetting to convert an
ArrayList<Integer>back into anint[]when required.
Expert Tips
Collectors.partitioningBy()is more appropriate thangroupingBy()when only two groups are required.- The same approach can separate elements based on any boolean condition, not just even and odd.
- Primitive arrays avoid the boxing and unboxing overhead associated with
Integerobjects, making them slightly more efficient for performance-critical applications.
Comparison Table
| Method | Passes Required | Output Type | Boxing Overhead |
|---|---|---|---|
| Two-Pass Primitive Arrays | 2 | int[] |
None |
| ArrayList | 1 | List<Integer> |
Yes |
Streams (partitioningBy) |
1 | Convertible to int[] |
Yes |
Frequently Asked Questions
Why are two passes required for primitive arrays?
Because Java arrays have a fixed size, you must count the even and odd elements before creating arrays of the correct length.
Can I avoid making two passes?
Yes. Using ArrayList allows the collection to grow dynamically, so only one pass is required.
How do I convert an ArrayList<Integer> into an int[]?
Use:
list.stream()
.mapToInt(Integer::intValue)
.toArray();
What does Collectors.partitioningBy() do?
It divides elements into two groups based on a boolean condition and returns a Map<Boolean, List<T>>.
Is ArrayList slower than primitive arrays?
Slightly, because it stores Integer objects instead of primitive int values, introducing boxing and unboxing overhead.
Can this technique separate elements using other conditions?
Yes. Simply replace the parity check with another condition, such as positive versus negative numbers or values greater than a threshold.
What happens if the input array is empty?
Both output arrays or lists will simply be empty.
Which approach is most commonly used in real-world Java applications?
ArrayList is generally preferred because it is simpler and avoids the need for two passes. Primitive arrays are mainly used when maximum performance or API compatibility is required.