How to Flatten a HashMap?

被刻印的时光 ゝ 提交于 2019-12-08 14:17:39

问题


I have a nested HashMap in this form:

{key1=val1, key2=val2, 
    key3=[
            {key4=val4, key5=val5}, 
            {key6=val6, key7=val7} 
        ]
}

I now want to flatten that map, so that all entries are on the same level:

{key1=val1, key2=val2, key4=val4, key5=val5,key6=val6, key7=val7}

When I try

map.values().forEach(map.get("key3")::addAll);

as described in this post, I get the following error:

invalid method reference
  cannot find symbol
    symbol:   method addAll(T)
    location: class Object
  where T is a type-variable:
    T extends Object declared in interface Iterable

Is there any generic way to flatten any given Map?


回答1:


Not sure if I understood the question correctly, but something like this might work. Haven't checked all the syntax yet, so there might be some mistake somewhere.

Stream<Map.Entry<String, String>> flatten(Map<String, Object> map) {
  return map.entrySet()
            .stream()
            .flatMap(this::extractValue);         
}

Stream<Map.Entry<String, String>> extractValue(Map.Entry<String, Object> entry) {
   if (entry.getValue() instanceof String) {
      return Stream.of(new AbstractMap.SimpleEntry(entry.getKey(), (String) entry.getValue()));
   } else if (entry.getValue() instanceof Map) {
      return flatten((Map<String, Object>) entry.getValue());
   }
}

Then you could do:

Map<String, String> flattenedMap = flatten(yourmap)
   .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));



回答2:


You can make use of a recursive helper method:

static void forEachValue(Map<String, Object> source, BiConsumer<? super String, ? super Object> action) {
    for (final Map.Entry<String, Object> entry : source.entrySet()) {
        if (entry.getValue() instanceof Map) {
            forEachValue((Map<String, Object>) entry.getValue(), action);
        } else {
            action.accept(entry.getKey(), entry.getValue());
        }
    }
}

Which then can be called like this:

Map<String, Object> map = ...;

Map<String, Object> flattened = new HashMap<>();
forEachValue(map, map::put);

I've used this approach with the BiConsumer to not limit the method to only flatten the nested map into another map, but the caller may decide himself what he wants to do with every key-value pair.




回答3:


You should try this:

Map<String, Object> flatenedMap = new HashMap<>();

    map.forEach((key, value) -> {
      if(value instanceof Map) {
        flatenedMap.putAll((Map) value);
      } else {
        flatenedMap.put(key, value);
      }
    });

If you have more than one level of nesting you can use recursive alg.

static Map<String, Object> flatMap(Map<String, Object> map) {
    Map<String, Object> flatenedMap = new HashMap<>();
    map.forEach((key, value) -> {
      if(value instanceof Map) {
        flatenedMap.putAll(flatMap((Map) value));
      } else {
        flatenedMap.put(key, value);
      }
    });

    return flatenedMap;
  }


来源:https://stackoverflow.com/questions/54183766/how-to-flatten-a-hashmap

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!