usar streams procesamiento parte lambdas expresiones explicacion example ejemplos datos con como java lambda java-8 java-stream

streams - java 8 lambdas pdf



Filtrado lambda de Java 8 basado en condición y orden (4)

Estaba tratando de filtrar una lista basada en múltiples condiciones, ordenando.

class Student{ private int Age; private String className; private String Name; public Student(int age, String className, String name) { Age = age; this.className = className; Name = name; } public int getAge() { return Age; } public void setAge(int age) { Age = age; } public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } public String getName() { return Name; } public void setName(String name) { Name = name; } }

Ahora si tengo una lista de eso, di

List<Student> students = new ArrayList<>(); students.add(new Student(24, "A", "Smith")); students.add(new Student(24, "A", "John")); students.add(new Student(30, "A", "John")); students.add(new Student(20, "B", "John")); students.add(new Student(24, "B", "Prince"));

¿Cómo podría obtener una lista de los alumnos más antiguos con un nombre distinto? En C #, esto sería bastante simple usando System.Linq GroupBy luego comparando y luego aplanando con select, no estoy muy seguro de cómo podría lograr lo mismo en Java.


O sin arroyos:

Map<String, Student> map = new HashMap<>(); students.forEach(x -> map.merge(x.getName(), x, (oldV, newV) -> oldV.getAge() > newV.getAge() ? oldV : newV)); Collection<Student> max = map.values();


Si necesitas una agrupación solo ordenada, es bastante simple:

Map<String, List<Student>> collect = students.stream() // stream capabilities .sorted(Comparator.comparingInt(Student::getAge).reversed()) // sort by age, descending .collect(Collectors.groupingBy(Student::getName)); // group by name.

Salida en cobro:

  • Prince = [Estudiante [Edad = 24, className = B, Name = Prince]],
  • Smith = [Estudiante [Edad = 24, nombre de clase = A, Nombre = Smith]]
  • Juan = [Estudiante [Edad = 30, nombre de clase = A, Nombre = Juan], Estudiante [Edad = 24, nombre de clase = A, Nombre = Juan], Estudiante [Edad = 20, nombre de clase = B, Nombre = Juan]]

Solo para mezclar y fusionar las otras soluciones, podría alternativamente hacer:

Map<String, Student> nameToStudentMap = new HashMap<>(); Set<Student> finalListOfStudents = students.stream() .map(x -> nameToStudentMap.merge(x.getName(), x, (a, b) -> a.getAge() > b.getAge() ? a : b)) .collect(Collectors.toSet());


Utilice el colector toMap :

Collection<Student> values = students.stream() .collect(toMap(Student::getName, Function.identity(), BinaryOperator.maxBy(Comparator.comparingInt(Student::getAge)))) .values();

Explicación

Estamos usando esta sobrecarga de toMap :

toMap​(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<U> mergeFunction)

  • Student::getName arriba es la función keyMapper utilizada para extraer los valores de las claves del mapa.
  • Function.identity() anterior es la función valueMapper utilizada para extraer los valores de los valores del mapa donde Function.identity() simplemente devuelve los elementos en la fuente ellos mismos, es decir, los objetos de Student .
  • BinaryOperator.maxBy(Comparator.comparingInt(Student::getAge)) es la función de combinación que se usa para "decidir qué objeto de Student devolver en el caso de una colisión de claves, es decir, cuando dos alumnos dados tienen el mismo nombre" en este caso tomando el Student más antiguo
  • Finalmente, invocar values() nos devuelve una colección de alumnos.

El código C # equivalente es:

var values = students.GroupBy(s => s.Name, v => v, (a, b) => b.OrderByDescending(e => e.Age).Take(1)) .SelectMany(x => x);

Explicación (para aquellos que no están familiarizados con .NET)

Estamos usando este método de extensión de GroupBy :

System.Collections.Generic.IEnumerable<TResult> GroupBy<TSource,TKey,TElement,TResult> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,TKey> keySelector, Func<TSource,TElement> elementSelector, Func<TKey,System.Collections.Generic.IEnumerable<TElement>,TResult> resultSelector);

  • s => s.Name anterior es la función keySelector utilizada para extraer el valor para agrupar por.
  • v => v anterior es la función elementSelector utilizada para extraer los valores, es decir, el Student opone a ellos mismos.
  • b.OrderByDescending(e => e.Age).Take(1) anterior es el IEnumerable<Student> resultSelector que, dado un IEnumerable<Student> representado como b toma el alumno más antiguo.
  • Finalmente, aplicamos .SelectMany(x => x); para contraer el IEnumerable<IEnumerable<Student>> resultante en un IEnumerable<Student> .