Java 8 list to display with stream

I have a collection of List<Item> . I need to convert it to Map<Integer, Item> map key should be the index of the item in the collection. I cannot figure out how to do this with threads. Something like:

 items.stream().collect(Collectors.toMap(...)); 

Any help?

Since this question is identified as a possible duplicate, I need to add that my specific problem was how to get the position of the item in the list and put it as a key value

+46
java collections dictionary java-8 java-stream
Sep 30 '15 at 6:13
source share
6 answers

You can create Stream indexes using IntStream , and then convert them to Map :

 Map<Integer,Item> map = IntStream.range(0,items.size()) .boxed() .collect(Collectors.toMap (i -> i, i -> items.get(i))); 
+45
Sep 30 '15 at 6:16
source share

Another solution for completeness is to use a custom collector:

 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; }); } 

Using:

 Map<Integer, Item> map = items.stream().collect(toMap()); 

This solution is compatible with the parallel and is independent of the source (you can use a list without random access or Files.lines() or something else).

+12
Sep 30 '15 at 10:41
source share

This is an updated answer and none of the problems mentioned in the comments.

 Map<Integer,Item> outputMap = IntStream.range(0,inputList.size()).boxed().collect(Collectors.toMap(Function.identity(), i->inputList.get(i))); 
+7
Sep 30 '15 at 6:28
source share

Do not feel that you need to do everything in / out with the stream. I would just do:

 AtomicInteger index = new AtomicInteger(); items.stream().collect(Collectors.toMap(i -> index.getAndIncrement(), i -> i)); 

Until you parallelize the stream, this will work, and this will avoid the potentially expensive and / or problematic (in the case of duplicate) get() and indexOf() operations.

(Instead of AtomicInteger you cannot use the int variable because the variables used from outside the lambda expression must be effectively final. Note that when uncontested (as in this case), AtomicInteger very fast and will not present performance problems But if this bothers you, you can use a counter that is not dependent on the thread.)

+7
Sep 30 '15 at 10:02
source share

Using a third-party library ( protonpack , for example, but there are others), you can zip value with your index and voila:

 StreamUtils.zipWithIndex(items.stream()) .collect(Collectors.toMap(Indexed::getIndex, Indexed::getValue)); 

although getIndex returns a long , so you might need to drop it using something similar to:

 i -> Integer.valueOf((int) i.getIndex()) 
+1
Sep 30 '15 at 15:01
source share

Eran's answer is generally the best approach for random access lists.

If your List not random access or you have Stream instead of List , you can use forEachOrdered :

 Stream<Item> stream = ... ; Map<Integer, Item> map = new HashMap<>(); AtomicInteger index = new AtomicInteger(); stream.forEachOrdered(item -> map.put(index.getAndIncrement(), item)); 

This is safe if the thread is parallel, although the destination map is unsafe and works as a side effect. forEachOrdered ensures that items are processed in turn, in order. For this reason, it is unlikely that any acceleration will be the result of parallel operation. (Some acceleration may happen if there are expensive operations in front of the forEachOrdered pipeline).

+1
03 Oct '15 at 1:33
source share



All Articles