2

I have the following maps.

Map<String,String> map1= new HashMap<String, String>(){{
       put("no1","123"); put("no2","5434"); put("no5","234");}};

Map<String,String> map1 = new HashMap<String, String>(){{
       put("no1","523"); put("no2","234"); put("no3","234");}};

sum(map1, map2);

I want to join them to one, summing up similar keyed values together. What;s the best way I could do it using java 7 or guava libraries ?

expected output

Map<String, String> output = { { "no1" ,"646"}, { "no2", "5668"}, {"no5","234"}, {"no3","234" }  }
Njax3SmmM2x2a0Zf7Hpd
  • 1,354
  • 4
  • 22
  • 44

4 Answers4

3
private static Map<String, String> sum(Map<String, String> map1, Map<String, String> map2) {
        Map<String, String> result = new HashMap<String, String>();
        result.putAll(map1);
        for (String key : map2.keySet()) {
            String value = result.get(key);
            if (value != null) {
                Integer newValue = Integer.valueOf(value) + Integer.valueOf(map2.get(key));
                result.put(key, newValue.toString());
            } else {
                result.put(key, map2.get(key));
            }
        }
        return result;
    }
shem
  • 4,686
  • 2
  • 32
  • 43
  • That works certainly but I think he was hoping for a neater solution. (Of course there may not be one.) – Rup Jul 01 '13 at 09:19
  • Agree, but I don't think there is any. If that's not good enough (in performance I mean) try to change your data model. – shem Jul 01 '13 at 09:25
  • 2
    As microoptimization (or a good habit) [use `Integer.valueOf` instead of `new Integer`](http://stackoverflow.com/questions/2974561/new-integer-vs-valueof). – Grzegorz Rożniecki Jul 01 '13 at 09:42
  • If you assume that both input maps have the same keys this can be simplified, but not sure you can assume that. – user949300 Oct 02 '14 at 19:49
2

try this

    Map<String, List<String>> map3 = new HashMap<String, List<String>>();
    for (Entry<String, String> e : map1.entrySet()) {
        List<String> list = new ArrayList<String>();
        list.add(e.getValue());
        String v2 = map2.remove(e.getKey());
        if (v2 != null) {
            list.add(v2);
        }
        map3.put(e.getKey(), list);
    }

    for (Entry<String, String> e : map2.entrySet()) {
        map3.put(e.getKey(), new ArrayList<String>(Arrays.asList(e.getValue())));
    }
Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275
  • 1
    I like this more than the other solution because it avoids iterating over the map1 keys twice, but it does mutate / destroy map2 in the process which might not be acceptable (and may have a non-trivial cost in itself, e.g. if deleting from a TreeMap causing rebalancing) – Rup Jul 01 '13 at 09:25
2

Java 8 introduces Map.merge(K, V, BiFunction), which makes this easy if not particularly concise:

Map<String, String> result = new HashMap<>(map1);
//or just merge into map1 if mutating it is okay
map2.forEach((k, v) -> result.merge(k, v, (a, b) ->
    Integer.toString(Integer.parseInt(a) + Integer.parseInt(b))));

If you're doing this repeatedly, you're going to be parsing and creating a lot of strings. If you're generating the maps one at a time, you're best off maintaining a list of strings and only parsing and summing once.

Map<String, List<String>> deferredSum = new HashMap<>();
//for each map
mapN.forEach((k, v) ->
    deferredSum.computeIfAbsent(k, x -> new ArrayList<String>()).add(v));
//when you're done
Map<String, String> result = new HashMap<>();
deferredSum.forEach((k, v) -> result.put(k,
    Long.toString(v.stream().mapToInt(Integer::parseInt).sum())));

If this summing is a common operation, consider whether using Integer as your value type makes more sense; you can use Integer::sum as the merge function in that case, and maintaining lists of deferred sums would no longer be necessary.

Jeffrey Bosboom
  • 13,313
  • 16
  • 79
  • 92
1

Try this

    Map<String,String> map1= new HashMap<String, String>(){{
        put("no1","123"); put("no2","5434"); put("no5","234");}};
    Map<String,String> map2 = new HashMap<String, String>(){{
        put("no1","523"); put("no2","234"); put("no3","234");}};
    Map<String,String> newMap=map1;
    for(String a:map2.keySet()){
       if(newMap.keySet().contains(a)){
               newMap.put(a,""+(Integer.parseInt(newMap.get(a))+Integer.parseInt(map2.get(a))));
       }
        else{
            newMap.put(a,map2.get(a));
        }
    }
    for(String k : newMap.keySet()){
        System.out.println("key : "+ k + " value : " + newMap.get(k));
    }
Ruchira Gayan Ranaweera
  • 34,993
  • 17
  • 75
  • 115
  • `Map newMap=map1` doesn't copy the map: it'll just assign a new reference to the existing map, i.e. you're merging map2 into the existing map1 and losing the original map1 state. Which might be acceptable, of course. – Rup Jul 01 '13 at 09:27
  • IF you want you can use Map newMap=new HashMap<>(); and newMap.putAll(map1) first :) – Ruchira Gayan Ranaweera Jul 01 '13 at 09:30