shanxxix shanxxix - 5 months ago 11
Java Question

How to assign recurring array elements as unique keys, and tally the corresponding integer values?

I've spent a while researching problems similar to mine, and am now stuck with my code. I have implemented a basic CSV file reader, but I'm stuck in processing the input

Current Result:

Source [medium = go bio , values = 5]
Source [medium = go bio , values = 5]
Source [medium = metal sink , values = 2]
Source [medium = go bio , values = 5]
Source [medium = metal sink , values = 3]
Done


But what I want is something like this.

Output:

[medium = go bio , values = 15]
[medium = metal sink , values = 5]


The contents of my text file.

go,bio,5
go,bio,5
metal,sink,2
go,bio,5
metal,sink,3


And this is my code:

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.FileReader;
import java.util.HashMap;

public class CVSReader {
public static void main(String[] args) {
CVSReader obj = new CVSReader();
obj.run();
}

public void run() {
String csvFile = "file2.txt";
BufferedReader br = null;
String line;
String cvsSplitBy = ",";
String[] source;

try {
//HashMap here
HashMap<String, String> hash = new HashMap<>();
HashMap<String, Integer> hash2 = new HashMap<>();

br = new BufferedReader(new FileReader(csvFile));
while ((line = br.readLine()) != null) {
// comma separator here
source = line.split(cvsSplitBy);

hash.put(source[0], source[0]);
hash.put(source[1], source[1]);
hash.put(source[2], source[2]);

System.out.println("Source [medium = " + hash.get(source[0]) + " " +
hash.get(source[1]) + " , values = " + hash.get(source[2]) + "]");
}

} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
System.out.println("Done");
}
}

Answer

First, you need a Map<String, Integer> to add your entries with the same key. Build the key, parse the value from your line, and if it's already in the Map add the current value to your parsed value. Then store the value back in the Map. I would also prefer a try-with-resources close. Finally, iterate the Map.entrySet(). Something like,

String csvFile = "file2.txt";
String cvsSplitBy = "\\s*,\\s*"; // <-- adds support for white space(s)
                                 //     before or after the comma.
try (BufferedReader br = new BufferedReader(new FileReader(csvFile))) {
    Map<String, Integer> hash = new HashMap<>();

    String line;
    while ((line = br.readLine()) != null) {
        String[] source = line.split(cvsSplitBy);
        String medium = source[0] + " " + source[1]; // <-- the key
        int val = Integer.parseInt(source[2]);       // <-- the value
        if (hash.containsKey(medium)) { // <-- is the key in Map?
            val += hash.get(medium);    // <-- yes, add the value.
        }
        hash.put(medium, val); // <--  store the value back in the Map.
    }
    // Iterate the entry set, display the "medium" and value.
    for (Map.Entry<String, Integer> entry : hash.entrySet()) {
        System.out.printf("Source [medium = %s , values = %d]%n",
                entry.getKey(), entry.getValue());
    }
} catch (IOException e) { // <-- FileNotFoundException is a sub-class.
    e.printStackTrace();
}
System.out.println("Done");

Which I ran with your provided text file, and got (as requested)

Source [medium = metal sink, values = 5]
Source [medium = go bio, values = 15]
Done