Skip to content

Instantly share code, notes, and snippets.

@aslakhellesoy
Created October 9, 2012 13:28
Show Gist options
  • Save aslakhellesoy/3858814 to your computer and use it in GitHub Desktop.
Save aslakhellesoy/3858814 to your computer and use it in GitHub Desktop.
Merge two maps in Java
// This is fancier than Map.putAll(Map)
public Map deepMerge(Map original, Map newMap) {
for (Object key : newMap.keySet()) {
if (newMap.get(key) instanceof Map && original.get(key) instanceof Map) {
Map originalChild = (Map) original.get(key);
Map newChild = (Map) newMap.get(key);
original.put(key, deepMerge(originalChild, newChild));
} else {
original.put(key, newMap.get(key));
}
}
return original;
}
@megabites2013
Copy link

java 8 Map has a merge() now

@SvaponiAkelius
Copy link

I do not think this handles Collection(s) properly :/ ..I guess we want to merge also collections, append all items of value (such as value = newMap[key] && value.type == Collection) to original value (such as original_value = original[key] && original_value.type == Collection)

@SvaponiAkelius
Copy link

SvaponiAkelius commented Jun 5, 2019

Check out this

    /**
     * @param target original map, the one with the side effect
     * @param source source map, the one with new data to be merged into #target
     */
    public static void mergeWithSideEffect(final Map<String, Object> target, final Map<String, Object> source) {
        source.forEach((key, sourceObj) -> {
            Object targetObj = target.get(key);
            if (sourceObj instanceof Map && targetObj instanceof Map) {
                mergeWithSideEffect((Map) targetObj, (Map) sourceObj);
            } else if (sourceObj instanceof List && targetObj instanceof List) {
                final List<Object> temp = new ArrayList<Object>((List) targetObj);
                mergeWithSideEffect(temp, (List) sourceObj);
                targetObj = temp;
            } else if (sourceObj instanceof Set && targetObj instanceof Set) {
                final Set<Object> temp = new HashSet<>((Set) targetObj);
                mergeWithSideEffect(temp, (Set) sourceObj);
                targetObj = temp;
            }
            target.put(key, sourceObj);
        });
    }

    private static void mergeWithSideEffect(final Collection target, final Collection source) {
        source.stream()
                .filter(item -> !target.contains(item))
                .forEach(target::add);
    }

I use temp variables because -often in my case- collections are originally immutable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment