Datos de partición de Java 8 de una lista a dos listas separadas [duplicado]
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
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).
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
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);