blue-sky
blue-sky

Reputation: 53806

Using Lambda Map function instead of iteration to populate Map

Below code converts List of Strings where the key and value are separated by "." to type Map<String, java.util.List<String>>

public static void main(String args[]) {

        java.util.List<String> l = new java.util.ArrayList<String>();
        l.add("key1.value1");
        l.add("key1.value2");
        l.add("key2.value3");

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

        l.forEach(line -> {
            String[] sa = line.split("\\.");
            List<String> ls = map.get(sa[0]);
            if (ls == null) {
                List<String> initial = new ArrayList<String>();
                initial.add(sa[1]);
                map.put(sa[0], initial);
            } else {
                ls.add(sa[1]);
            }
        });

        for (Entry<String, List<String>> entry : map.entrySet()) {
            String key = entry.getKey();
            List<String> value = entry.getValue();
            System.out.println(key+","+StringUtils.join(value , ","));
        }
    }

Is there a better approach using java lambdas ? Possibly using map function ?

Note : StringUtils is part of commons-lang lib :

<dependency>
    <groupId>commons-lang</groupId>
    <artifactId>commons-lang</artifactId>
    <version>2.3</version>
</dependency>

Upvotes: 2

Views: 681

Answers (2)

Tagir Valeev
Tagir Valeev

Reputation: 100199

The correct stream version should use the groupingBy collector:

Map<String, List<String>> map = l.stream().map(s -> s.split("\\."))
        .map(s -> s.length > 1 ? s : new String[] {s[0], ""})
        .collect(
             Collectors.groupingBy(s -> s[0], 
                 Collectors.mapping(s -> s[1], 
                     Collectors.toList())));

Also note that in Java-8 there's String.join method, so you don't need the StringUtils to print the result:

map.entrySet().stream()
    .map(e -> e.getKey()+","+String.join(",", e.getValue()))
    .forEach(System.out::println);

Upvotes: 5

marstran
marstran

Reputation: 28026

You can do this:

l.stream()
 .map(s -> s.split("\\."))
 .collect(Collectors.toMap(s -> s[0], s -> s[1], (a, b) -> b));

The last function is a merge-function which tells it to just pick the last value if two keys are equal. Not providing this function will throw an IllegalStateException if there are duplicate keys.

If you need a map from Strings to a list of Strings with the same keys. You can use the Collectors.groupingBy method (as in Tagir Valeev's answer).

Upvotes: 3

Related Questions