Nooblhu Nooblhu - 1 month ago 15
Java Question

Iterating a Map<TypeA,Set<TypeB>> and convert it to a Map<TypeB,Set<TypeA>> in Java

I have a

Map<String>,Set<String>> followingMap
, where the keys are usernames and values are Sets of usernames that the key usernames follows.
I have to create a followersMap , where in this case, the followed users in the value Sets are now the keys and the value is a Set of followers according to the previous k.

Not sure if this is clear enough so as an example, an element in the followingMap would be:
key="john", value=Set["robert","andrew,"amanda"].


In the followersMap it would be:

key="robert", value=Set["john"]
key="andrew", value=Set["john"]
key="amanda", value=Set["john"]


If a second element in followingMap is
key="alex",Set["amanda"]
that would add "alex" to the value Set of the "amanda" key.

My code should do the trick, however when testing, I'm getting keys where all value Set are being filled.

Take a look:

Map<String,Set<String>> followerGraph = new HashMap<String,Set<String>>();
for (Map.Entry<String, Set<String>> me : followsGraph.entrySet()) {
String key = me.getKey();
Set<String> tmp = new LinkedHashSet<>();
Set<String> valueSet = me.getValue();
for (String s : valueSet) {
if (followerGraph.containsKey(s)){
followerGraph.get(s).add(key);
} else {
tmp.add(key);
followerGraph.put(s, tmp);
}
}
}


So this is the print of the followsGraph:

{aliana=[@jake, @john, @erick], alyssa=[@john, @erick],
bbitdiddle=[@rock-smith, @john, @erick], casus=[@daniel, @jake, @john, @erick],
david=[@dude, @john]}


And this is the print of the followerGraph:

{@daniel=[casus], @rock-smith=[bbitdiddle], @jake=[aliana, alyssa, bbitdiddle, casus, david], @dude=[david], @john=[aliana, alyssa, bbitdiddle, casus, david], @erick=[aliana, alyssa, bbitdiddle, casus, david]}


As you can see, @erick shouln't have david as follower. Am I missing something?
Sorry if my code looks like a mess. I have just 6 months in Java, 4 hours learning how to iterate a map (tried the Java 8 streams but not sure how to add the if-else in there), and it's 6 am and my wife might kill me for staying up all night :S

Answer

You can do something like that:

    Map<String, Set<String>> followerMap = new HashMap<>();
    followingMap.forEach((name,followingSet)-> followingSet.forEach(
            follower-> followerMap.computeIfAbsent(follower, f->new HashSet<>())
                                  .add(name)));

followingMap.forEach process all the entries in the followingMap. Then the Set of each entry is being processed with followingSet.forEach. The elements of this set are the followers, the keys of the new map. computeIfAbsent is being used to put a new entry in the map if it doesn't exists, adding an empty Set in that case. Afterthat, the value is added to the Set, in that case the entry of the followerMap.

And this is the same code using for loops instead of forEach, probably more readable.

    Map<String, Set<String>> followerMap = new HashMap<>();
    for (Entry<String, Set<String>> followingEntry : followingMap.entrySet()) {
        for (String follower : followingEntry.getValue()) {
            followerMap.computeIfAbsent(follower, s->new HashSet<>()).add(followingEntry.getKey());
        }
    }