'How to convert a Map<String,List<String>> to Map<String,Set<String>> using forEach operation

I want to convert a Map<String,List<String>> to Map<String,Set<String>> for optimized search. I came up with the below traditional approach.

 for (Map.Entry<String, List<String>> entry : this.mapWithList.entrySet()) {
        Set<String> hSet = new HashSet<>(entry.getValue());
        this.mapWithSet.put(entry.getKey(), hSet);
   }

I am wondering how can I do it using forEach in Java 8.

Also, with the forEach lambda, will it be any better with the code performance?



Solution 1:[1]

will it be any better with the code performance?

No, it'll not. Iterative solutions are usually more performant.

how can I do it using forEach

There's a special operation collect() in the Stream API that is meant to populate a mutable container (e.g. Collection, StringBuilder, etc.) with the contents of the stream pipeline. Usage of forEach() for that purpose is highly discouraged by the documentation. Consider utilizing forEach() only as a last resort, when there's no other way to achieve that.

To do that with collect(), first, you need to create a stream of entries.

Based on each entry, a new entry has to be created, map() operation is utilized for that purpose. Static method Map.entry() is used to instantiate a new entry.

And then apply the terminal operation collect() by passing Collectors.toMap() as parameter, which creates a collector (object responsible for placing the stream elements into a mutable container, a map in this case) based on the two provided functions (for keys and values).

main()

public static void main(String[] args) {
    Map<String,List<String>> mapWithList =
            Map.of("1", List.of("1", "2", "3"));

    Map<String,Set<String>> result =
       mapWithList.entrySet().stream()
                  .map(entry -> Map.entry(entry.getKey(),
                            new HashSet<>(entry.getValue())))
                  .collect(Collectors.toMap(Map.Entry::getKey,
                                            Map.Entry::getValue));
    System.out.println(result);
}

Output

{1=[1, 2, 3]}

Solution 2:[2]

You can use this approach:

public static void main(String[] args) {
        Map<String, List<String>> inputMap = new HashedMap<>();
        List<String> a = new ArrayList<>();
        a.add("a1");
        a.add("a2");
        inputMap.put("a", a);

        List<String> b = new ArrayList<>();
        b.add("b1");
        b.add("b2");

        inputMap.put("b", b);

        System.out.println(inputMap);

        Map<String, Set<String>> resultSet= inputMap.entrySet().stream()
                .collect(Collectors.toMap(Entry::getKey, e -> new HashSet<>(e.getValue())));

        System.out.println(resultSet);
    }

Solution 3:[3]

one line solution using gson! (or any other JSON serializer)

Map<String, Set<String>> result = gson.fromJson(gson.toJson(otherMap), Map.class);

both maps have the same JSON representation. think outside the box ;)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Sachin Bose
Solution 3