Search code examples
javalisthashmapjava-streamiteration

Streams use for map computation from list with counter


I have the following for loop which I would like to replace by a simple Java 8 stream statement:

List<String> words = new ArrayList<>("a", "b", "c");
Map<String, Long> wordToNumber = new LinkedHashMap<>();
Long index = 1L;

for (String word : words) {
  wordToNumber.put(word, index++);
}

I basically want a sorted map (by insertion order) of each word to its number (which is incremented at each for loop by 1), but done simpler, if possible with Java 8 streams.


Solution

  • The following should work (though it's not clear why Long is needed because the size of List is int)

    Map<String, Long> map = IntStream.range(0, words.size())
        .boxed().collect(Collectors.toMap(words::get, Long::valueOf));
    

    The code above works if there's no duplicate in the words list.

    If duplicate words are possible, a merge function needs to be provided to select which index should be stored in the map (first or last)

    Map<String, Long> map = IntStream.range(0, words.size())
        .boxed().collect(
            Collectors.toMap(words::get, Long::valueOf, 
            (w1, w2) -> w2, // keep the index of the last word as in the initial code
            LinkedHashMap::new // keep insertion order
        ));
    

    Similarly, the map can be built by streaming words and using external variable to increment the index (AtomicLong and getAndIncrement() may be used instead of long[]):

    long[] index = {1L};
    Map<String, Long> map = words.stream()
        .collect(
            Collectors.toMap(word -> word, word -> index[0]++, 
            (w1, w2) -> w2, // keep the index of the last word
            LinkedHashMap::new // keep insertion order
        ));