multiple conditions java filter lambda java-8

conditions - java 8 map



¿Cómo obtener una gama de elementos de la transmisión con Java 8 lambda? (2)

Para obtener un rango de Stream<T> , puede usar skip(long n) para omitir primero un número determinado de elementos, y luego puede llamar al limit(long n) para tomar solo una cantidad específica de elementos.

Considera una transmisión con 10 elementos, luego para obtener los elementos 3 a 7, normalmente llamarías desde una List :

list.subList(3, 7);

Ahora, con un Stream , primero debe omitir 3 elementos, y luego tomar 7 - 3 = 4 elementos, por lo que se convierte en:

stream.skip(3).limit(4);

Como una variante de la solución de @StuartMarks a la segunda respuesta, le ofreceré la siguiente solución que deja intacta la posibilidad de encadenar, funciona de manera similar a como lo hace @StuartMarks:

private <T> Collector<T, ?, Stream<T>> topPercentFromRangeCollector(Comparator<T> comparator, double from, double to) { return Collectors.collectingAndThen( Collectors.toList(), list -> list.stream() .sorted(comparator) .skip((long)(list.size() * from)) .limit((long)(list.size() * (to - from))) ); }

y

IntStream.range(0, 100) .boxed() .collect(topPercentFromRangeCollector(Comparator.comparingInt(i -> i), 0.1d, 0.3d)) .forEach(System.out::println);

Esto imprimirá los elementos 10 a 29.

Funciona mediante el uso de un Collector<T, ?, Stream<T>> que toma sus elementos de la secuencia, los transforma en una List<T> , luego obtiene una Stream<T> , la ordena y aplica la (correcta) límites a eso.

En una pregunta anterior [ ¿Cómo hacer dinámicamente el filtrado en Java 8? ] Stuart Marks dio una respuesta maravillosa y proporcionó varias utilidades útiles para manejar la selección de topN y topPercent de la transmisión.

Los incluiré aquí de su respuesta original:

@FunctionalInterface public interface Criterion { Stream<Widget> apply(Stream<Widget> s); } Criterion topN(Comparator<Widget> cmp, long n) { return stream -> stream.sorted(cmp).limit(n); } Criterion topPercent(Comparator<Widget> cmp, double pct) { return stream -> { List<Widget> temp = stream.sorted(cmp).collect(toList()); return temp.stream() .limit((long)(temp.size() * pct)); }; }

Mis preguntas aquí son:

[1] Cómo obtener los elementos principales del 3 al 7 de una transmisión con cierta cantidad de elementos, de modo que si la transmisión tiene elementos de A1, A2 ... A10, la llamada a

topNFromRange(Comparator<Widget> cmp, long from, long to) = topNFromRange(comparing(Widget::length), 3L, 7L)

devolverá {A3, A4, A5, A6, A7}

La forma más sencilla en que puedo pensar es obtener los 7 mejores [T7] del original, obtener los 3 primeros [T3] del original, y luego obtener T7 - ​​T3.

[2] Cómo obtener los elementos principales del 10% superior al 30% superior de una transmisión con cierta cantidad de elementos, de modo que si la transmisión tiene elementos de X1, X2 ... X100, la llamada a

topPercentFromRange(Comparator<Widget> cmp, double from, double to) = topNFromRange(comparing(Widget::length), 0.10, 0.30)

devolverá {X10, X11, X12, ..., X29, X30}

La forma más sencilla en que puedo pensar es obtener el 30% [TP30] superior del original, obtener el 10% [TP10] superior del original, y luego obtener TP30 - TP10.

¿Cuáles son algunas formas mejores de utilizar Java 8 Lambda para expresar de forma concisa las situaciones anteriores?


El usuario Skiwi ya respondió la primera parte de la pregunta. La segunda parte es:

(2) Cómo obtener los artículos principales del 10% superior al 30% superior de una transmisión con cierta cantidad de artículos ....

Para hacer esto, debes usar una técnica similar a topPercent en mi respuesta a la otra pregunta. Es decir, debe recopilar los elementos en una lista para poder contar los elementos, posiblemente después de que se haya realizado un cierto filtrado ascendente.

Una vez que tiene el recuento, calcula los valores correctos para skip y limit función del recuento y los porcentajes que desee. Algo como esto podría funcionar:

Criterion topPercentFromRange(Comparator<Widget> cmp, double from, double to) { return stream -> { List<Widget> temp = stream.sorted(cmp).collect(toList()); return temp.stream() .skip((long)(temp.size() * from)) .limit((long)(temp.size() * (to - from))); }; }

Por supuesto, tendrá que hacer una comprobación de errores from y to . Un problema más sutil es determinar cuántos elementos emitir. Por ejemplo, si tiene diez elementos, están en índices [0..9], que corresponden a 0%, 10%, 20%, ..., 90%. Pero si pidieras un rango del 9% al 11%, el código anterior no emitiría ningún elemento, no el que está al 10% como podrías esperar. Así que es probable que algunos retoques con los cálculos porcentuales sean necesarios para ajustarse a la semántica de lo que estás tratando de hacer.