java - programacion - Obtener el último elemento de Stream/List en un solo trazo
curso android desarrollo de aplicaciones móviles pdf (7)
Como lo menciona @nosid, se puede hacer usando reducir. Otra forma de hacerlo sería invertir el flujo y luego obtener el primer elemento
CArea last = data.careas.stream()
.filter(c -> c.bbox.orientationHorizontal)
.sorted((a, b)-> -1)
.findFirst().get();
¿Cómo puedo obtener el último elemento de una secuencia o lista en el siguiente código?
Donde data.careas
es una List<CArea>
:
CArea first = data.careas.stream()
.filter(c -> c.bbox.orientationHorizontal).findFirst().get();
CArea last = data.careas.stream()
.filter(c -> c.bbox.orientationHorizontal).collect(Collectors.toList()).; //how to?
Como puede ver, obtener el primer elemento, con un cierto filter
, no es difícil.
Sin embargo, obtener el último elemento en una sola línea es un verdadero dolor:
- Parece que no puedo obtenerlo directamente de un
Stream
. (Tendría sentido solo para flujos finitos) - También parece que no se puede obtener cosas como
first()
ylast()
desde la interfaz deList
, lo cual es realmente un problema.
No veo ningún argumento para no proporcionar un first()
y last()
método en la interfaz de la List
, ya que los elementos allí están ordenados, y además se conoce el tamaño.
Pero según la respuesta original: ¿Cómo obtener el último elemento de un Stream
finito?
Personalmente, esto es lo más cerca que podría estar:
int lastIndex = data.careas.stream()
.filter(c -> c.bbox.orientationHorizontal)
.mapToInt(c -> data.careas.indexOf(c)).max().getAsInt();
CArea last = data.careas.get(lastIndex);
Sin embargo, implica el uso de un indexOf
en cada elemento, lo cual es probable que no desee, ya que puede perjudicar el rendimiento.
Como no está claro si es parte de la especificación API para reduce
obedecer orden de encuentro, ¿qué pasa con:
CArea last = data.careas.stream()
.filter(c -> c.bbox.orientationHorizontal)
.max((e1, e2) -> data.careas.indexOf(e1) - data.careas.indexOf(e2)).get();
Es posible obtener el último elemento con el método Stream::reduce . La siguiente lista contiene un ejemplo mínimo para el caso general:
Stream<T> stream = ...; // sequential or parallel stream
Optional<T> last = stream.reduce((first, second) -> second);
Esta implementación funciona para todas las secuencias ordenadas (incluidas las secuencias creadas a partir de Lists ). Para las secuencias unordered , por razones obvias, no se especifica qué elemento se devolverá.
La implementación funciona tanto para secuencias secuenciales como paralelas . Eso podría sorprender a primera vista, y desafortunadamente la documentación no lo dice explícitamente. Sin embargo, es una característica importante de las transmisiones, y trato de aclararlo:
- El Javadoc para el método Stream::reduce estados, que " no está obligado a ejecutarse secuencialmente " .
- El Javadoc también requiere que la "función del acumulador debe ser una función asociativa , no interferente , sin estado para combinar dos valores" , que obviamente es el caso para la expresión lambda
(first, second) -> second
. - El Javadoc para operaciones de reducción establece: "Las clases de flujos tienen múltiples formas de operaciones generales de reducción, llamadas Stream::reduce y collect() [..]" y "una operación de reducción construida correctamente es inherentemente paralelizable , siempre que la función (s) ) utilizados para procesar los elementos son associative y stateless ".
La documentación para los Collectors estrechamente relacionados es aún más explícita: "Para garantizar que las ejecuciones secuenciales y paralelas produzcan resultados equivalentes , las funciones de recopilador deben satisfacer una identidad y una associative restricciones".
Volver a la pregunta original: el siguiente código almacena una referencia al último elemento en la last
variable y arroja una excepción si la transmisión está vacía. La complejidad es lineal en la longitud de la secuencia.
CArea last = data.careas.stream()
.filter(c -> c.bbox.orientationHorizontal)
.reduce((first, second) -> second).get();
Puede usar java.util.Collections
usando el siguiente método estático:
Collections.max(yourList);
De documentos:
Devuelve el elemento máximo de la colección dada, de acuerdo con el * orden natural de sus elementos. [...]
Si tiene una Colección (o, en general, una Iterable) puede usar Google Guava''s
Iterables.getLast(myIterable)
como práctico en elineador.
También puede usar la función skip () como se muestra a continuación ...
long count = data.careas.count();
CArea last = data.careas.stream().skip(count - 1).findFirst().get();
es súper simple de usar.
Un trazador de líneas (sin necesidad de transmisión);
Object lastElement = list.get(list.size()-1);