Как выровнять HashMap? - PullRequest
       10

Как выровнять HashMap?

0 голосов
/ 14 января 2019

У меня есть вложенное HashMap в этой форме:

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

Теперь я хочу сгладить эту карту, чтобы все записи были на одном уровне:

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

Когда я пытаюсь

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

как описано в этом посте , я получаю следующую ошибку:

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

Есть ли какой-нибудь общий способ сгладить любое данное Map?

Ответы [ 3 ]

0 голосов
/ 14 января 2019

Не уверен, правильно ли я понял вопрос, но что-то вроде этого может сработать. Еще не проверили весь синтаксис, так что где-то может быть какая-то ошибка.

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());
   }
}

Тогда вы можете сделать:

Map<String, String> flattenedMap = flatten(yourmap)
   .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
0 голосов
/ 14 января 2019

Вы можете использовать рекурсивный вспомогательный метод:

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());
        }
    }
}

Что тогда можно назвать так:

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

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

Я использовал этот подход с BiConsumer, чтобы не ограничивать метод только сведением вложенной карты в другую карту, но вызывающий может сам решить, что он хочет делать с каждой парой ключ-значение.

0 голосов
/ 14 января 2019

Вы должны попробовать это:

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

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

Если у вас более одного уровня вложенности, вы можете использовать рекурсивный алгоритм.

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;
  }
...