I get a stream of some custom objects and I would like to create a map Map<Integer, MyObject>
with index of each object as key. To give you a simple example:
Stream<String> myStream = Arrays.asList("one","two","three").stream();
Integer i = 0;
Map<Integer, String> result3 = myStream.collect(Collectors.toMap(x -> i++, x -> x));
Obviously, this doesn't compile because:
local variables referenced from a lambda expression must be final or effectively final
Is there a simple way to map elemnts of a stream to their indices so that the expected output for above example is something like:
{1=one, 2=two, 3=three}
Create an AtomicInteger for index. Get the Stream from the array using Arrays. stream() method. Map each elements of the stream with an index associated with it using map() method where the index is fetched from the AtomicInteger by auto-incrementing index everytime with the help of getAndIncrement() method.
The map() function is a method in the Stream class that represents a functional programming concept. In simple words, the map() is used to transform one object into other by applying a function. That's why the Stream. map(Function mapper) takes a function as an argument.
You can use stream() method of the List interface which gives a stream to iterate using forEach method. In forEach method, we can use the lambda expression to iterate over all elements. The following code snippet shows the usage of streams to iterate over the list. list.
You can use an IntStream
to solve this:
List<String> list = Arrays.asList("one","two","three");
Map<Integer, String> map = IntStream.range(0, list.size()).boxed()
.collect(Collectors.toMap(Function.identity(), list::get));
You create an IntStream
from 0
to list.size() - 1
(IntStream.range()
excludes the last value from the stream) and map each index to the value in your list. The advantage of this solution is, that it will also work with parallel streams, which is not possible with the use of an AtomicInteger
.
So the result in this case would be:
{0=one, 1=two, 2=three}
To start the first index at 1
you can just add 1
during collect:
List<String> list = Arrays.asList("one", "two", "three");
Map<Integer, String> map = IntStream.range(0, list.size()).boxed()
.collect(Collectors.toMap(i -> i + 1, list::get));
This will result in this:
{1=one, 2=two, 3=three}
You i
variable is not effectively final.
You can use AtomicInteger
as Integer
wrapper:
Stream<String> myStream = Arrays.asList("one","two","three").stream();
AtomicInteger atomicInteger = new AtomicInteger(0);
Map<Integer, String> result3 = myStream.collect(Collectors.toMap(x -> atomicInteger.getAndIncrement(), Function.identity()));
I consider it a bit hacky because it only solves the problem of effectively final variable. Since it is a special ThreadSafe version it might introduce some overhead. Pure stream
solution in the answer by Samuel Philipp might better fit your needs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With