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:

Advertisement

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 ArrayList when 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> into int[] using stream().mapToInt(Integer::intValue).toArray() when needed.
  • Use Collectors.partitioningBy() for concise stream-based solutions.

Common Mistakes

  1. Trying to create both arrays in a single pass without knowing their required sizes.
  2. Forgetting to maintain separate indices for the even and odd arrays.
  3. Attempting to create ArrayList<int>, which is invalid because Java generics work only with objects.
  4. Forgetting to convert an ArrayList<Integer> back into an int[] when required.

Expert Tips

  • Collectors.partitioningBy() is more appropriate than groupingBy() 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 Integer objects, 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.