2017-02-17 10 views
1

Речь идет о Java, но для удобства чтения я собираюсь записать примеры в JSON.Как объединить несколько карт по значению определенного ключа?

Скажем, у меня есть List из Map, настроил так:

[{ 
    "id": 1, 
    "foo": 12, 
    "bar": 34 
}, { 
    "id": 1, 
    "baz": 56 
}, { 
    "id": 2, 
    "foo": 78 
}, { 
    "id": 2, 
    "bar": 90 
}] 

То, что я хотел бы сделать, это объединить карты, которые имеют тот же id. В принципе, я хочу, чтобы в конечном итоге с чем-то вроде этого:

[{ 
    "id": 1, 
    "foo": 12, 
    "bar": 34, 
    "baz": 56 
}, { 
    "id": 2, 
    "foo": 78, 
    "bar": 90 
}] 

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

Этого код, кажется, работает, но меня поражает, как мало подробный вывод:

List<Map<String, Integer>> toRemove = new ArrayList<Map<String, Integer>>(); 

for (Map<String, Integer> map : list) { 
    if (toRemove.contains(map)) { 
     continue; 
    } 
    int id = map.get("id"); 
    for (Map<String, Integer> otherMap : list) { 
     if (map.equals(otherMap)) { 
      continue; 
     } 
     int otherId = otherMap.get("id"); 
     if (id == otherId) { 
      map.putAll(otherMap); 
      toRemove.add(otherMap); 
     } 
    } 
} 

list.removeAll(toRemove); 

Есть ли более элегантный способ для достижения этой цели?

+0

в вашем примере нет ни одного случая, в котором карты с той же долей ид ключа (в данном случае значения должны быть SUMED я думаю). Это гарантировано? – fustaki

+0

Это будет O (n * n) и медленное для большого набора данных. Один из подходов состоит в том, что вы можете сортировать список на основе id и объединиться, пока не получите тот же идентификатор. – theBeacon

+0

@fustaki Я могу предположить, что они не разделяют ключи, кроме «id», и если бы они это сделали, все было бы хорошо просто заменить любой из них. – vvye

ответ

3

Я бы организовать результат в Map Карт

Map<Integer, Map<String,Integer>> mapOfMaps = new HashMap<Integer, Map<String,Integer>>(); 

for(Map<String,Integer> map : list){ 
    Integer id = map.get("id"); 
    Map<String,Integer> existingMap = mapOfMaps.get(id); 
    if(existingMap == null){ 
     mapOfMaps.put(id, map); 
    }else{ 
     existingMap.putAll(map); 
    } 
} 

Как я заметил выше: это в случае, если вы не нужно суммировать значения (кроме id карт не разделяют другие ключи или если они значения будут заменены)

+0

Я думаю, что это сработает красиво - в результате «Карта» - это аккуратная идея. Благодаря! – vvye

2

Просто сделайте groupMap, что является новой карты, с id ключ и элемент карты значение:

List<Map<String, Integer>> toRemove = new ArrayList<Map<String, Integer>>(); 
    Map<Integer, Map<String, Integer>> groupMap = new HashMap<>(); 

    for (Map<String, Integer> m : toRemove) { 
     Integer id = m.get("id"); 
     Map<String, Integer> tmp = groupMap.get(id); 
     if (tmp == null) { 
      groupMap.put(id, m); 
     } else { 
      tmp.putAll(m); 
     } 
    } 

    List<Map<String, Integer>> newList = new ArrayList<>(groupMap.values()); 

Затем ваш newList.

1

Мой сrazy решение с потоками:

List<Map<String, Integer>> result = list.stream() 
     .collect(Collectors.groupingBy(m -> m.get("id"))) 
     .values().stream() 
     .map(m -> m.stream().<Map<String, Integer>>collect(HashMap::new, Map::putAll, Map::putAll)) 
     .collect(Collectors.toList());