2

I have deriving two separate groups from a list, error data and error free data:

List<ProductHolder> errorOnes = holderList.stream()
                                                      .filter(holder-> (holder.getRecord().isX() || holder.getRecord().isY()))
                                                      .collect(Collectors.toList());

List<ProductHolder> nonErrorOnes = holderList.stream()
                                                      .filter(holder-> (!holder.getRecord().isX() && !holder.getRecord().isY()))
                                                      .collect(Collectors.toList());

The above has multiple calls to .stream().

Is there a way I can partition the above into separate lists using single call to .stream() ? Is there a performance gain in doing so?

how to then access these data? I presume I need to hold use a Map?

M06H
  • 1,675
  • 3
  • 36
  • 76

2 Answers2

3

First of all, your two conditions do not partition the original List. i.e. the second condition is not the negation of the first.

If you want a true partitioning, you can use Collectors.partitioningBy:

Map<Boolean, List<ProductHolder>> partition = 
    holderList.stream()
              .collect(Collectors.partitioningBy(holder-> (holder.getRecord().isX() || holder.getRecord().isY())));

The first partition (that satisfies the condition) will be obtained via partition.get(true), and the second via partition.get(false).

Eran
  • 387,369
  • 54
  • 702
  • 768
  • updated the condition. would the answer still apply ? – M06H Oct 28 '20 at 13:40
  • @M06H Yes (except for the first sentence that addressed the old version). See [Collectors.partitioningBy](https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/stream/Collectors.html#partitioningBy(java.util.function.Predicate)) – Hulk Oct 28 '20 at 13:41
  • @M06H yes, now `partition.get(true)` would contain the elements of `errorOnes` and `partition.get(false)` the elements of `nonErrorOnes`. – Eran Oct 28 '20 at 13:42
0

Intro

You can use Java 8 Collectors partitioningBy. So you could split your list into a map of lists and then get the two lists from there.

Short Solution

Map<Boolean, List<ProductHolder>> groups =
            holderList.stream().collect(Collectors.groupingBy(s ->!s.getRecord().isX() && !s.getRecord().isY()));
    
    List<ProductHolder> resultOne = groups.get(true);
    List<ProductHolder> resultTwo = groups.get(false);

Full Example

@Data @Builder
    static
    class ProductHolder{
        PRecord record;
    }

    @Data @Builder
    static class PRecord{
        boolean x;  boolean y;
    }


  List<ProductHolder> holderList = new ArrayList<>() {{
                add(ProductHolder.builder().record(PRecord.builder().x(true).y(false).build()).build());
                add(ProductHolder.builder().record(PRecord.builder().x(true).y(true).build()).build());
                add(ProductHolder.builder().record(PRecord.builder().x(false).y(false).build()).build());
                add(ProductHolder.builder().record(PRecord.builder().x(false).y(false).build()).build());
                add(ProductHolder.builder().record(PRecord.builder().x(false).y(false).build()).build());
            }};

Map<Boolean, List<ProductHolder>> groups =
                holderList.stream().collect(Collectors.groupingBy(s ->!s.getRecord().isX() && !s.getRecord().isY()));

        List<ProductHolder> resultOne = groups.get(true);
        List<ProductHolder> resultTwo = groups.get(false);

References

https://www.baeldung.com/java-list-split

Menelaos
  • 23,508
  • 18
  • 90
  • 155