jdk - ¿Hay un método aggregateBy en la secuencia Java 8 api?
java api 8 throwable (3)
Ejecutar esta presentación muy interesante pero de un año de duración de Brian Goetz: en la diapositiva vinculada presenta un método aggregateBy()
supuestamente en Stream API, que se supone debe agregar los elementos de una lista (?) A un mapa (dado un valor inicial predeterminado y un método para manipular el valor (también para las claves duplicadas) - ver la siguiente diapositiva en la presentación).
Aparentemente, no existe dicho método en Stream API . ¿Hay algún otro método que haga algo análogo en Java 8?
Digamos que tenemos una lista de empleados con su departamento y salario y queremos el salario total pagado por cada departamento.
Hay varias formas de hacerlo y, por ejemplo, puede usar un recopilador toMap
para agregar los datos por departamento:
- el primer argumento es el mapeador de claves (su eje de agregación = el departamento),
- el segundo es el mapeador de valor (los datos que desea agregar = sueldos), y
- el tercero es la función de fusión (cómo desea agregar datos = sumar los valores).
Ejemplo:
import static java.util.stream.Collectors.*;
public static void main(String[] args) {
List<Person> persons = Arrays.asList(new Person("John", "Sales", 10000),
new Person("Helena", "Sales", 10000),
new Person("Somebody", "Marketing", 15000));
Map<String, Double> salaryByDepartment = persons.stream()
.collect(toMap(Person::department, Person::salary, (s1, s2) -> s1 + s2));
System.out.println("salary by department = " + salaryByDepartment);
}
Como ocurre a menudo con las transmisiones, hay varias formas de obtener el resultado deseado, por ejemplo:
import static java.util.stream.Collectors.*;
Map<String, Double> salaryByDepartment = persons.stream()
.collect(groupingBy(Person::department, summingDouble(Person::salary)));
Como referencia, la clase de persona:
static class Person {
private final String name, department;
private final double salary;
public Person(String name, String department, double salary) {
this.name = name;
this.department = department;
this.salary = salary;
}
public String name() { return name; }
public String department() { return department; }
public double salary() { return salary; }
}
Esta entrada particular de Javadoc es lo más parecido que pude encontrar en esta pieza de agregación en Java 8. Aunque es una API de terceros, las firmas parecen alinearse bastante bien: usted proporciona alguna función para obtener valores, alguna función terminal para valores (cero, en este caso), y alguna función para combinar la función y los valores juntos.
Se parece mucho a un Coleccionista , que nos ofrecería la posibilidad de hacer esto.
Map<String, Integer> strIntMap =
intList.stream()
.collect(Collectors
.groupingBy(Document::getAuthor,
Collectors.summingInt(Document::getPageCount)));
La idea entonces es que agrupemos el nombre del autor para cada entrada de nuestra lista y sumemos el total de los números de página que tiene el autor en un Map<String, Integer>
.
La operación agregada se puede hacer usando la clase de Collectors
. Entonces, en el video, el ejemplo sería equivalente a:
Map<String, Integer> map =
documents.stream().collect(Collectors.groupingBy(Document::getAuthor, Collectors.summingInt(Document::getPageCount)));
El método groupingBy
te dará un Map<String, List<Document>>
. Ahora tiene que usar un recopilador en sentido descendente para sumar todo el recuento de páginas para cada documento en la List
asociada a cada tecla.
Esto se hace proporcionando un recopilador en sentido descendente a groupingBy
, que es summingInt
, lo que da como resultado un Map<String, Integer>
.
Creo que eliminaron esta operación y crearon la clase Collectors
lugar para tener una clase útil que contiene muchas reducciones que usará comúnmente.