# Split Collection to two list depend on criteria

Let's say I have a List contains numbers:

1,2,3,4,5,6,7,8,9

and I would like to split this to two lists:

• odd numbers
• even numbers

So I can do this two ways:

Solution 1:

Create two methods:

List<Integer> filterOdd(List<Integer> numbers){
List<Integer> result  = new ArrayList<Integer>();
for(Integer n : numbers){
if(n % 2 != 0){
}
}
return result;
}

List<Integer> filterEven(List<Integer> numbers){
List<Integer> result  = new ArrayList<Integer>();
for(Integer n : numbers){
if(n % 2 == 0){
}
}
return result;
}


and in the code I will call:

List<Integer> numbers = Arrays.asList(new Integer[] { 1,2,3,4,5,6,7,8,9 });

List<Integer> oddNumbers = filterOdd(numbers);
List<Integer> evenNumbers = filterEven(numbers);


and do something with these lists.

I do two loops over one collection.

Solution 2:

Create one method:

public void filter(List<Integer> numbers, List<Integer> oddNumbers, List<Integer> evenNumbers){
for(Integer n : numbers){
if(n % 2 != 0){
}else{
}
}
}


and in the code I will call:

List<Integer> numbers = Arrays.asList(new Integer[] { 1,2,3,4,5,6,7,8,9 });
List<Integer> oddNumbers  = new ArrayList<Integer>();
List<Integer> evenNumbers = new ArrayList<Integer>();
filter(numbers, oddNumbers, evenNumbers);


I hear that assigning results for parameters is bad practice.

Which solution is better?

• "Disadvantage: I hear that assign results for parameters is a bad practice." <-- where did you read that? If it is the most practical for you, just use it...
– fge
Jun 24, 2013 at 12:51
• I think the first one is better. Not only because it is most reusable, but because the second one can be created also by making calls to the 2 methods of the first solution Jun 24, 2013 at 15:43
• Assigning to parameters is definitely an abomination. But it is not what the OP does here. So that principle, however true, just do not apply here. Calling a method on a parameter is not an assignment. Jun 25, 2013 at 13:02

As already mentioned in the other answers, in Java 8 you can use lambdas and the stream API to remove a lot of boilerplate.

Both your solutions can be converted to use streams.

Solution 1 - two methods:

public List<Integer> oddNumbers(List<Integer> numbers) {
return numbers.stream().filter(n -> (n % 2) != 0).collect(Collectors.toList());
}

public List<Integer> evenNumbers(List<Integer> numbers) {
return numbers.stream().filter(n -> (n % 2) == 0).collect(Collectors.toList());
}


Solution 2 - as single method:

public void filter(List<Integer> numbers, List<Integer> oddNumbers, List<Integer> evenNumbers) {
Map<Boolean, List<Integer>> partitions = numbers.stream().collect(Collectors.partitioningBy(n -> (n % 2) == 0));
}

• For solution 1, you can even pass the predicate as a parameter, and then just one method will be enough. Jun 17, 2018 at 4:57

If you only need to split collection into 2 pieces by a certain criterion, then there's a built-in collector to achieve this:

 final List<Integer> numbers = asList(1, 2, 3, 4, 5);
final Map<Boolean, List<Integer>> lists = numbers.stream().collect(Collectors.partitioningBy(n -> n % 2 == 0));
System.out.println(lists.get(true));
System.out.println(lists.get(false));


This will print:

  [2, 4]
[1, 3, 5]

• Indeed the solution I would go with. Also, in case of more than two options (so not a Boolean), there's also various groupingBy functions. Feb 1, 2020 at 14:47

Here is a solution which replicates Guava's Predicate interface. Since this interface is really easy, here is how it is done:

public interface Predicate<T>
{
// returns true if input obeys the predicate
boolean apply(T input);
}


Given this interface, implement it for your types; and then do a method like this:

public static <T> List<List<T>> filteredLists(final List<T> list,
final List<Predicate<T>> predicates)
{
final int size = predicates.size();
final List<List<T>> ret = new ArrayList<List<T>>(size);

// Fill ret with initial lists
for (int i = 0; i < size; i++)

// Now walk the predicates and add to the necessary lists

for (final T element: list)
for (int i = 0; i < size; i++)
if (predicates.get(i).apply(element))

// Done! Return...
return ret;
}


Now, if you had a utility class, say MyPredicates, with two methods even() and odd(), you could write:

final List<List<Integer>> filtered = filteredList(inputList,
Arrays.asList(MyPredicates.even(), MyPredicates.odd()));


The "drawback" here is that it is up to the caller to remind what predicates where in what order in the calling lists, of course.

As to your MyPredicates hypothetical class:

public static final class MyPredicates
{
// No instansiation
private MyPredicates()
{
}

public static Predicate<Integer> even()
{
return new Predicate<Integer>()
{
@Override
public boolean apply(final Integer input)
{
return input.intValue() % 2 == 0;
}
}
}

public static Predicate<Integer> odd()
{
return new Predicate<Integer>()
{
@Override
public boolean apply(final Integer input)
{
return input.intValue() % 2 == 1;
}
}
}
}


Go for two methods :

• In fact, Java 8 will have Predicate... They have salvaged quite a few interfaces from Guava for that matter. Hurray!