usar programacion listmodel item codigo java dictionary collections java-8 java-stream

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 ).