Home > other >  Java Merge Nested HashMaps at the innermost/leaf level
Java Merge Nested HashMaps at the innermost/leaf level

Time:03-11

Say I got 2 Key Value pairs:

String k1 = "a.b.c.d";
String v1 = "123";
String k2 = "a.b.c.d";
String v2 = "456";

And the desired output is:

a {
  b {
    c {
      d = "123",
      e = "456"
    }
  }
}

So, I've decided the split the keys by "." and form nested HashMaps and then trying to merge them when they have duplicate keys. However, it needs to merge at the leaf or innermost level instead of the outermost level.

This is the full code:

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import java.util.stream.Stream;


public class TestClass {
    public static void main(String []args)
    {
        Map<String, Object> finalMap = new HashMap<>();
        Map<String, Object> outerMap1 = new HashMap<>();
        Map<String, Object> outerMap2 = new HashMap<>();
        String k = "a.b.c.d";
        String v = "123";
   
        outerMap1 = createNestedStructure(k, v);
        
        k = "a.b.c.e";
        v = "456";
        outerMap2 = createNestedStructure(k, v);

        
        finalMap = Stream
                .concat(outerMap1.entrySet().stream(),
                        outerMap2.entrySet().stream())
                .collect(Collectors.toMap(Entry::getKey,
                        Entry::getValue, (a, b) -> {
                            String c = a.toString()   "\n"   b.toString();
                            return c;
                        }, HashMap::new));
       
        System.out.println(finalMap.toString());
   }
   public static Map<String, Object> createNestedStructure(String k, String v)
   {
       String[] tokens = k.split("\\.");
       Map<String, String> innerMap = new HashMap<>();
       v = "\""   v   "\"";
       innerMap.put(tokens[tokens.length-1], v);
       
       Map<String, Object> middleMap = new HashMap<>();
       middleMap.put(tokens[tokens.length-2], innerMap);
       for(int i=tokens.length-3; i>=0; i--)
       {
           Map<String, Object> middleMapTmp = new HashMap<>();
           middleMapTmp.put(tokens[i], middleMap);
           middleMap = middleMapTmp;
       }
//       Map<String, Object> outerMap = new HashMap<>();
//       outerMap.put(tokens[0], middleMap);
//       return outerMap;
       return middleMap;
   }
}

I'm not sure if this is the correct approach. So suggestions on better approaches are also welcome.

CodePudding user response:

Not exactly sure about your specific problem, but you could simply insert the values into the same structure instead of merging them afterward. For example, you can make a recursive insert that creates the nested maps until it inserts your value on the last key part. If the nested map already exists it uses the existing one. Something like this could do the trick:

public static void main(String[] args) {
    String k1 = "a.b.c.d";
    String v1 = "123";
    String k2 = "a.b.c.e";
    String v2 = "456";

    Map<String, Object> map = new HashMap<>();
    recursiveInsert(map,k1, v1);
    recursiveInsert(map,k2, v2);

    System.out.println(map);
}

public static void recursiveInsert(Map<String, Object> map, String key, String value) {
    int index = key.indexOf('.');
    if (index == -1) {
        map.put(key, value);
    } else {
        String subKey = key.substring(0, index);
        map.putIfAbsent(subKey, new HashMap<>());
        recursiveInsert((Map<String, Object>) map.get(subKey), key.substring(index   1), value);
    }
}

The output of this is what you requested:

{a={b={c={d=123, e=456}}}}
  • Related