user10179187
user10179187

Reputation: 119

Can we collect two lists from Java 8 streams?

Consider I have a list with two types of data,one valid and the other invalid.

If I starting filter through this list, can i collect two lists at the end?

Upvotes: 10

Views: 20000

Answers (5)

prasad_
prasad_

Reputation: 14317

One way using Java 8 streams API is to use the Collectors.partitioningBy collector.

Consider I have a List of String elements: the input list has strings with various lengths; only strings with length 3 are valid.

List<String> input = Arrays.asList("one", "two", "three", "four", "five");
Map<Boolean, List<String>> map =
        input.collect(Collectors.partitioningBy(s -> s.length() == 3));
System.out.println(map); // {false=[three, four, five], true=[one, two]}

List<String> valid = map.get(true);    // [one, two]
List<String> invalid = map.get(false); // [three, four, five]

The resulting Map has only two records; one with valid and the other with not-valid input list elements. The map record with key=true has the valid string as a List: one, two. The other is a key=false and the not-valid strings: three, four, five.

Note that Collectors.partitioningBy produces always two records in the resulting map irrespective of the existence of valid or not-valid values.

Upvotes: 8

art
art

Reputation: 183

If you need to classify binary (true|false), you can use Collectors.partitioningBy that will return Map<Boolean, List> (or other downstream collection like Set, if you additionally specify).

If you need more than 2 categories - use groupBy or just Collectors.toMap of collections.

Upvotes: 1

GhostCat
GhostCat

Reputation: 140613

The collector can only return a single object!

But you could create a custom collector that simply puts the stream elements into two lists, to then return a list of lists containing these two lists.

There are many examples how to do that.

Upvotes: 2

davidxxx
davidxxx

Reputation: 131516

Can we collect two lists from Java 8 streams?

You cannot but if you have a way to group elements of the Lists according to a condition. In this case you could for example use Collectors.groupingBy() that will return Map<Foo, List<Bar>> where the values of the Map are the two List.

Note that in your case you don't need stream to do only filter.

Filter the invalid list with removeIf() and add all element of that in the first list :

invalidList.removeIf(o -> conditionToRemove);
goodList.addAll(invalidList);      

If you don't want to change the state of goodList you can do a shallow copy of that :

invalidList.removeIf(o -> conditionToRemove);
List<Foo> terminalList = new ArrayList<>(goodList);
terminalList.addAll(invalidList);

Upvotes: 9

Stephen C
Stephen C

Reputation: 719551

Another suggestion: filter using a lambda that adds the elements that you want to filter out of the stream to a separate list.

Upvotes: 2

Related Questions