user1775213
user1775213

Reputation: 511

Merging Maps containing Sets throws UnsupportedOperationException

Here's the code:

private static Map<String, Set<String>> merge(Map<String, Set<String>> m1, Map<String, Set<String>> m2) {
    Map<String, Set<String>> mx = new HashMap<String, Set<String>>();
    for (Entry<String, Set<String>> entry : m1.entrySet()) {
        Set<String> otherMapValue = m2.get(entry.getKey());
        if (otherMapValue == null) {
            mx.entrySet().add(entry);
        } else {
            Set<String> merged = new HashSet<String>();
            merged.addAll(entry.getValue());
            merged.addAll(otherMapValue);
            mx.put(entry.getKey(), merged);
        }
    }
    return mx;
}

This throws the following error:

Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractCollection.add(Unknown Source)
at algorithms.NetworkBuilder.merge(NetworkBuilder.java:86)
at algorithms.NetworkBuilder.build(NetworkBuilder.java:38)
at algorithms.Main.main(Main.java:35)

I've only found solutions with maps that don't contain collections, they didn't work for me as I also need to merge the sets if a key occurs in both maps.
What I want to do is create a new map where every key contained one or both of the the two maps is mapped to the union of the lists it is mapped to in the original two maps.

Upvotes: 1

Views: 1181

Answers (2)

Jeffrey
Jeffrey

Reputation: 44808

Map::entrySet:

Returns a Set view of the mappings contained in this map. [...] The set supports element removal, which removes the corresponding mapping from the map, via the Iterator.remove, Set.remove, removeAll, retainAll and clear operations. It does not support the add or addAll operations.

Try mx.put(entry.getKey(), entry.getValue()) instead of mx.entrySet().add(entry).

If you're allowed to use third party libraries, consider using Guava's Multimap.

Comparison [of Multimaps] to a map of collections

Multimaps are commonly used in places where a Map<K, Collection<V>> would otherwise have appeared.

Multimap<String, String> m1 = ...
Multimap<String, String> m2 = ...

m1.putAll(m2); // merged!

Upvotes: 4

hosyvietanh
hosyvietanh

Reputation: 286

The problem of your code is in the line

mx.entrySet().add(entry);

The set you use only supports removal operations: http://docs.oracle.com/javase/7/docs/api/java/util/Map.html#entrySet()

You may want to change that line into

mx.put(entry.getKey(), entry.getValue());

Also, your method doesn't consider the keys that are in m2 but not in m1. You may want to loop through m2.entrySet() as well.

Upvotes: 2

Related Questions