Search code examples
javadictionaryhashmapnested

Summing values within a nested map based on a key that's outside of the inner map


  import java.util.*;

public class Orders {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        Map<String, Map<Double, Double>> myMap = new LinkedHashMap<String, Map<Double, Double>>();


        String input = "";
        while (true) {

            input = scanner.nextLine();
            String[] tokens = input.split(" ");
            String name = tokens[0];
            if ("buy".equals(name)) {
                break;
            }
            double price = Double.parseDouble(tokens[1]);
            double quantity = Double.parseDouble(tokens[2]);
            Map<Double, Double> innerMap = myMap.get(name);
            myMap.put(name, innerMap = new HashMap<>());


            innerMap.put(price, quantity);
            Double existingQuantity = innerMap.get(price);

            if (myMap.containsKey(name)) {
                innerMap.replace(innerMap.get(price), price);
                myMap.get(name).put(price, existingQuantity + quantity);
            }



        }
        System.out.println(myMap);
    }
}

Hello,

What I'm trying to do here is sum the value(quantity) of innerMap for each time a repeating key(name) from the outer map is inputted. I did a lot of research but didn't manage to find a case similar to mine.

For example, an input of

Water 1.20 500
Water 1.20 300
buy

Should yield

Water 1.20 800

Also sorry for my english.


Solution

  • It appears the you have to replace

    innerMap.put(price, quantity);
    

    with

    innerMap.merge(price, quantity, (q1,q2)->q1+q2);
    

    This way all the quantities that correspond with the same name and the same price will be summed.

    It also appears that you should change

    Map<Double, Double> innerMap = myMap.get(name);
    myMap.put(name, innerMap = new HashMap<>());
    

    to

    Map<Double, Double> innerMap = myMap.get(name);
    if (innerMap == null) {
        myMap.put(name, innerMap = new HashMap<>());
    }
    

    since you don't want to overwrite the inner Map of a given name each time you encounter that name.

    To summarize:

    while (true) {
        input = scanner.nextLine();
        String[] tokens = input.split(" ");
        String name = tokens[0];
        if ("buy".equals(name)) {
            break;
        }
        double price = Double.parseDouble(tokens[1]);
        double quantity = Double.parseDouble(tokens[2]);
        Map<Double, Double> innerMap = myMap.get(name);
        if (innerMap == null) {
            myMap.put(name, innerMap = new HashMap<>());
        }
        innerMap.merge(price, quantity, (q1,q2)->q1+q2);
    }
    

    And I believe this can be further simplified as follows:

    while (true) {
        input = scanner.nextLine();
        String[] tokens = input.split(" ");
        String name = tokens[0];
        if ("buy".equals(name)) {
            break;
        }
        double price = Double.parseDouble(tokens[1]);
        double quantity = Double.parseDouble(tokens[2]);
        myMap.computeIfAbsent(name,n -> new HashMap<>())
             .merge(price, quantity, (q1,q2)->q1+q2);
    }
    

    EDIT: For your request in the comment you'll have to keep replacing the key of the inner Maps:

    while (true) {
        input = scanner.nextLine();
        String[] tokens = input.split(" ");
        String name = tokens[0];
        if ("buy".equals(name)) {
            break;
        }
        double price = Double.parseDouble(tokens[1]);
        double quantity = Double.parseDouble(tokens[2]);
        Map<Double, Double> innerMap = myMap.computeIfAbsent(name,n -> new HashMap<>());
        if (innerMap.isEmpty()) {
            innerMap.put(price,quantity);
        } else {
            innerMap.put(price,quantity + innerMap.remove(innerMap.keySet().iterator().next()));
        }
    }