Datos de partición de Java 8 de una lista a dos listas separadas [duplicado]

Oct 28 2020

He derivado dos grupos separados de una lista, datos de error y datos sin errores:

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());

Lo anterior tiene varias llamadas a .stream().

¿Hay alguna manera de dividir lo anterior en listas separadas usando una sola llamada a .stream()? ¿Hay una mejora en el rendimiento al hacerlo?

¿cómo acceder a estos datos? ¿Supongo que necesito usar un mapa?

Respuestas

3 Eran Oct 28 2020 at 20:33

En primer lugar, sus dos condiciones no dividen el original List. es decir, la segunda condición no es la negación de la primera.

Si desea una verdadera partición, puede usar Collectors.partitioningBy:

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

La primera partición (que cumpla la condición) se obtendrá mediante partition.get(true)y la segunda mediante partition.get(false).

OptimalPrime Oct 28 2020 at 20:33

Intro

Puede utilizar los recopiladores Java 8 particionando por . Entonces, podría dividir su lista en un mapa de listas y luego obtener las dos listas desde allí.

Solución corta

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);

Ejemplo completo

@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);

Referencias

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

WJS Oct 28 2020 at 21:25

Aquí hay otra alternativa que se divide en las dos listas. Requiere un poco más de configuración, pero se presta a más que una elección binaria, si surge la necesidad. También asigna nombres significativos a las claves del mapa.

Primero, establezca un enum(Tenga en cuenta que los literales de cadena también se pueden usar en lugar de enum).

enum ErrorStatus {
        ERROR_ONES, NO_ERROR_ONES
}

Ahora defina una función para hacer la prueba. Esta prueba es necesaria independientemente. La lambda externa simplemente elimina los detalles del flujo, haciendo que el flujo esté menos "ocupado".

Esta función devuelve el tipo de enumeración adecuado según la condición.

Function<ProductHolder, ErrorStatus> errors =
        holder -> (holder.getRecord().isX()
                || holder.getRecord().isY()) ?
                        ErrorStatus.ERROR_ONES :
                        ErrorStatus.NO_ERROR_ONES;

Ahora crea el mapa basado en las pruebas.

Map<ErrorStatus, List<ProductHolder>> partitions =
        holderList.stream()
                .collect(Collectors.groupingBy(errors));

Obtener las listas sería como cualquier otro mapa: partitions.get(ErrorStatus.ERROR_ONES)o partitions.get(ErrorStatus.NO_ERROR_ONES);