2

I have a map Map<String, Set<String>>

Map<String, Set<String> result = map.entrySet().parallelStream().collect(
            Collectors.groupingBy(Map.Entry::getValue, Collectors.mapping(Map.Entry::getKey, Collectors.toSet())));

I want to convert it to Map<String, Set<String>> . by grouping the values and swapping the places of key and value.

But this line gives me

Type mismatch: cannot convert from Map<Object,Set<Object>> to Map<String,Set<String>>

7
  • You need to parse the value from Object to String. Commented Sep 18, 2018 at 11:09
  • Maybe like this ? Commented Sep 18, 2018 at 11:13
  • 1
    Your question title does not match your problem description. Further, you say you want to convert the map to Map<Set<String>, Set<String>>, but declare the result variable with an entirely different type (and there’s a > missing). So it’s not surprising that you get a compiler error. Commented Sep 18, 2018 at 12:07
  • @Holger maybe Type mismatch: cannot convert from Map<Object,Set<Object>> to Map<String,Set<String>> is the crux of it? agreed though there is clutter in the question. Commented Sep 18, 2018 at 12:09
  • 4
    @nullpointer as long as the OP doesn’t decide about what to convert to what, there is no point in thinking about the compiler error. There are three entirely different problem statements, the question’s title, the question’s text, and the code example. When I change the code example to match what the OP wrote in the textual description, there is no compiler error. Commented Sep 18, 2018 at 12:14

3 Answers 3

4

The problem that you've got here is the type of the map you are creating is:

Map<Set<String>, Set<String>>

not Map<String, Set<String>>.

As such, you need to expand the map's values first, for example:

Map<String, Set<String>> collect = map.entrySet()
    .parallelStream()
    // Expand (k, {v1, v2, v3}) to [(v1, k), (v2, k), (v3, k)]
    .flatMap(e -> e.getValue().stream().map(ee -> new SimpleEntry<>(ee, e.getKey())))
    .collect(
        Collectors.groupingBy(
            Map.Entry::getKey,
            Collectors.mapping(Map.Entry::getValue, Collectors.toSet())));

Unless you really need the parallel processing, I think it would be much easier to use loops:

Map<String, Set<String>> collect = new HashSet<>();
for (Map.Entry<String, Set<String>> entry : map.entrySet()) {
  for (String v : entry.values()) {
      collect.computeIfAbsent(v -> new HashSet<>())
              .add(entry.getKey()));
  }
}
Sign up to request clarification or add additional context in comments.

Comments

1

Here is an example considering your initial Map is Object to Object. Adapt as needed.

Map<Object,Object> map = new HashMap<>();
Map<String, Set<String>> result = map
            .entrySet()
            .parallelStream()
            .collect(Collectors.groupingBy(entry -> (String) entry.getKey(), 
                     Collectors.mapping(entry -> (String) entry.getKey(), Collectors.toSet())));

The problem with your code is that Map.Entry::getKey returns an Object, not a String.

3 Comments

I personally prefer entry.getKey().toString() rather than casting to a String, but have an upvote regardless. :) Of course, my method leaves you succeptable to NullPointerException (since some implementations of Map can have a null key, and obviously you can have a null value).
Note that you're not doing what OP wants (you're not using the map values at all).
Hi @alexrolea, your answer helped me. But like @AndyTurner mentioned It will generate Map<Set<String>, String<String>>
1

Just to avoid the confusion, I'm answering my question. Thanks to @AndyTurner @alexrolea for pointing out the solution.

Map<Set<String>, Set<String>> result = map.entrySet().parallelStream()
                .collect(
                Collectors.groupingBy(entry -> (Set<String>) entry.getValue(), 
                        Collectors.mapping(entry -> entry.getKey(), Collectors.toSet())));

I had to replace Map.Entry::getValue with entry -> (Set<String>) entry.getValue() and the other one too.

This helped me group the map by values and use them as keys. Thanks @nullpointer

In fact, this also works. The problem is I was not returning the right datatype.

Map<Set<String>, Set<String>> result = map.entrySet().parallelStream()
                .collect(
                Collectors.groupingBy(Map.Entry::getValue, 
                        Collectors.mapping(Map.Entry::getKey, Collectors.toSet())));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.