wutBruh
wutBruh

Reputation: 67

How to deal with same keys in HashMaps ?

Hello fellow soldiers.

Obviously keys in hashmaps are unique. However, I've been trying to write a code that reads a csv file and then puts the key and value in the map. However, there are keys the same (every key is like 15 times in the csv file). In that case, it should make a sum of the values, and just return the key once. How to do that? My code right now is as follows.

BufferedReader br = null;
String line;



    try {
        br = new BufferedReader(new FileReader(filepath)); 

    } catch (FileNotFoundException fnfex) {

        System.out.println(fnfex.getMessage() + "Bestand niet gevonden!");
        System.exit(0);
    }

    //this is where we read lines
    try {
        while((line = br.readLine()) != null) {
            String[] splitter = line.split(cvsSplitBy);

            if(splitter[0] != "Voertuig") {

                alldataMap.put(splitter[0], splitter[8]);

        }


            //MIGHT BE JUNK, DONT KNOW YET
            /*if((splitter[0].toLowerCase()).contains("1")){
                double valuekm = Double.parseDouble(splitter[8]);
                license1 += valuekm;
                System.out.println(license1);
            }
            else {
                System.out.println("not found");
            }*/


        }
        System.out.println(alldataMap);
        TextOutput();
    } catch (IOException ioex) {
        System.out.println(ioex.getMessage() + " Error 1");
    } finally {
        System.exit(0);
    }

So if I have the following info (in this case its the 0th and 8th word read every line in the csv file)

Apples; 299,9
Bananas; 300,23
Apples; 3912,1
Bananas;342
Bananas;343

It should return

Apples;Total
Bananas;Total

Upvotes: 0

Views: 382

Answers (5)

azro
azro

Reputation: 54168

I won't suggest the way to it in a loop because that's already done, but I'd suggest a Streams solution, in a unique line :

Map<String, Double> alldataMap = new HashMap<>();
try {
    alldataMap =
            Files.lines(Paths.get("", filepath))
                    .map(str -> str.split(cvsSplitBy))
                    .filter(splitte -> !splitte[0].equals("Voertuig"))
                    .collect(Collectors.toMap(sp -> sp[0],
                            sp -> Double.parseDouble(sp[8].replaceAll(",", ".")),
                            (i1, i2) -> i1 + i2));
} catch (IOException e) {
    e.printStackTrace();
}

System.out.println(alldataMap); // {Apples=4212.0, Bananas=985.23}

The steps are the same :

  • Iterate over the lines
  • split on the cvsSplitBy
  • remove lines which starts with Voertuig (! use .equals() and not !=)
  • build the map following 3 rules :
    • the key is the first String
    • the value is second String parsed as Double
    • if merge is required : sum both

Edit, as nobody propose the use of .getOrDefault() I give it

while ((line = br.readLine()) != null) {
    String[] splitter = line.split(cvsSplitBy);
    if (!splitter[0].equals("Voertuig")) {
        alldataMap.put(splitter[0],
           alldataMap.getOrDefault(splitter[0], 0.0) + 
                                    Double.parseDouble(splitter[8].replaceAll(",", ".")));
    }
}

If tke key already exists, it'll sum, it the key does not exists it'll sum the value with a 0

Upvotes: 1

Victor Gubin
Victor Gubin

Reputation: 2937

Try the following:

if( alldataMap.containsKey(splitter[0]) ) { 
  Double sum = alldataMap.remove(splitter[0]) + Double.parseDouble(splitter[8]);
  allDataMap.put(splitter[0], sum );
} else {
  alldataMap.put(splitter[0], Double.valueOf(splitter[8]) );
}

Upvotes: 3

Vyncent
Vyncent

Reputation: 1205

i would use the merge for a map :

alldataMap.merge(splitter[0], Double.valueOf(splitter[8]), (oldVal, newVal) -> oldVal + newVal);

From doc:

If the specified key is not already associated with a value or is associated with null, associates it with the given non-null value. Otherwise, replaces the associated value with the results of the given remapping function, or removes if the result is null. This method may be of use when combining multiple mapped values for a key. For example, to either create or append a String msg to a value mapping:

Upvotes: 1

Michael
Michael

Reputation: 44250

You can use putIfAbsent and compute since Java 8:

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

//...

String fruitName = /*whatever*/;
int qty = /*whatever*/;

myMap.putIfAbsent(fruitName, 0);
myMap.compute(fruitName, (k, oldQty) -> oldQty + qty);

Upvotes: 2

O.O.Balance
O.O.Balance

Reputation: 3040

You can use Map#containsKey() to check for an existing mapping, then if there is one use Map#get() to retrieve the value and add the new one, and finally Map#put() to store the sum:

if(map.containsKey(key))
    map.put(key, map.get(key)+value);
else
    map.put(key, value);

See here for the documentation of those methods.

Upvotes: 1

Related Questions