java - listmodel - manual de programacion android pdf
Lista de Java 8 para mapear con transmisiĆ³n (6)
Tengo una colección List<Item>
. Necesito convertirlo en Map<Integer, Item>
La clave del mapa debe ser el índice del artículo en la colección. No puedo entender cómo hacer esto con las transmisiones. Algo como:
items.stream().collect(Collectors.toMap(...));
¿Alguna ayuda?
Como esta pregunta se identifica como posible duplicado, debo agregar que mi problema concreto era cómo colocar la posición del elemento en la lista y ponerlo como valor clave.
Esta es una respuesta actualizada y no tiene ninguno de los problemas mencionados en los comentarios.
Map<Integer,Item> outputMap = IntStream.range(0,inputList.size()).boxed().collect(Collectors.toMap(Function.identity(), i->inputList.get(i)));
No sientas que tienes que hacer todo en / con la transmisión. Solo lo haría:
AtomicInteger index = new AtomicInteger();
items.stream().collect(Collectors.toMap(i -> index.getAndIncrement(), i -> i));
Siempre que no haga paralelo a la secuencia, esto funcionará y evitará operaciones potencialmente caras y / o problemáticas (en el caso de duplicados) get()
e indexOf()
.
(No se puede usar una variable int
regular en lugar de AtomicInteger
porque las variables utilizadas desde fuera de una expresión lambda deben ser efectivamente finales. Tenga en cuenta que cuando no se ha AtomicInteger
(como en este caso), AtomicInteger
es muy rápido y no representará un problema de rendimiento. Pero si le preocupa, puede usar un contador que no sea seguro para subprocesos).
Puede crear un Stream
de los índices usando un IntStream
y luego convertirlos a un Map
:
Map<Integer,Item> map =
IntStream.range(0,items.size())
.boxed()
.collect(Collectors.toMap (i -> i, i -> items.get(i)));
Una solución más para completar es utilizar coleccionista personalizado:
public static <T> Collector<T, ?, Map<Integer, T>> toMap() {
return Collector.of(HashMap::new, (map, t) -> map.put(map.size(), t),
(m1, m2) -> {
int s = m1.size();
m2.forEach((k, v) -> m1.put(k+s, v));
return m1;
});
}
Uso:
Map<Integer, Item> map = items.stream().collect(toMap());
Esta solución es paralela y no depende de la fuente (puede usar la lista sin acceso aleatorio o Files.lines()
o lo que sea).
Utilizando una biblioteca de terceros ( protonpack por ejemplo, pero hay otros) puede zip
el valor con su índice y listo:
StreamUtils.zipWithIndex(items.stream())
.collect(Collectors.toMap(Indexed::getIndex, Indexed::getValue));
a pesar de que getIndex
devuelve un valor long
, por lo que es posible que deba getIndex
utilizando algo similar a:
i -> Integer.valueOf((int) i.getIndex())
La respuesta de Eran suele ser el mejor enfoque para las listas de acceso aleatorio.
Si su List
no es de acceso aleatorio, o si tiene un Stream
lugar de una List
, puede usar forEachOrdered
:
Stream<Item> stream = ... ;
Map<Integer, Item> map = new HashMap<>();
AtomicInteger index = new AtomicInteger();
stream.forEachOrdered(item -> map.put(index.getAndIncrement(), item));
Esto es seguro, si el flujo es paralelo, a pesar de que el mapa de destino no es seguro para el hilo y se opera como un efecto secundario. El forEachOrdered
garantiza que los artículos se procesen uno a la vez, en orden. Por esta razón, es poco probable que se produzca una aceleración al ejecutarse en paralelo. (Puede haber alguna aceleración si hay operaciones costosas en la tubería antes de forEachOrdered
).