Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Transform List into Map using only two keys and odd or even list indexes as values - Java 8 Stream

I would like to transform list into map using as key values only two string values. Then as values just list of strings containing elements from odd or even index positions from input list. Here is old fashion code:

Map<String, List<String>> map = new HashMap<>();

List<String> list = Arrays.asList("one", "two", "three", "four");

map.put("evenIndex", new ArrayList<>());
map.put("oddIndex", new ArrayList<>());
for (int i = 0; i < list.size(); i++) {
    if(i % 2 == 0)
        map.get("evenIndex").add(list.get(i));
    else 
        map.get("oddIndex").add(list.get(i));
}

How to transform this code into Java 8 using streams to get this result?

{evenIndex=[one, three], oddIndex=[two, four]}

My current messy attempt require modifying elements of list, but definitly must be better option.

List<String> listModified = Arrays.asList("++one", "two", "++three", "four");

map = listModified.stream()
           .collect(Collectors.groupingBy(
                               str -> str.startsWith("++") ? "evenIndex" : "oddIndex"));

Or maybe someone help me with this incorrect solution?

IntStream.range(0, list.size())
         .boxed()
         .collect(Collectors.groupingBy( i -> i % 2 == 0 ? "even" : "odd",
                  Collectors.toMap( (i -> i ) , i -> list.get(i) ) )));

which return this:

{even={0=one, 2=three}, odd={1=two, 3=four}}
like image 301
wokadakow Avatar asked Aug 19 '17 18:08

wokadakow


2 Answers

You were on the right track with streaming over the indexes:

import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.toList;

IntStream.range(0,list.size())
        .boxed()
        .collect(groupingBy(
                i -> i % 2 == 0 ? "even" : "odd", 
                mapping(list::get, toList())
        ));

If you are ok with having your map be indexed by a boolean you can use partitioningBy:

IntStream.range(0, list.size())
        .boxed()
        .collect(partitioningBy(
                i -> i % 2 == 0, 
                mapping(list::get, toList())
        ));
like image 181
Misha Avatar answered Oct 26 '22 11:10

Misha


You can achieve the same thing with Collectors.toMap; just for the fun of it:

Map<String, List<String>> map = IntStream.range(0, list.size())
            .boxed()
            .collect(Collectors.toMap(
                    x -> x % 2 == 0 ? "odd" : "even",
                    x -> {
                        List<String> inner = new ArrayList<>();
                        inner.add(list.get(x));
                        return inner;
                    },
                    (left, right) -> {
                        left.addAll(right);
                        return left;
                    },
                    HashMap::new));

    System.out.println(map);
like image 20
Eugene Avatar answered Oct 26 '22 09:10

Eugene