if I have the following CSV file
how can I split the item name and the quantity and ignore the shop name, in a hashmap list?
This is what I have done so far:
public class ListRead {
HashMap<String, Integer> csvList = new HashMap<>();
public void loadManifest() throws IOException {
FileReader ListCSV = new FileReader("list.csv");
BufferedReader reader = new BufferedReader(ListCSV);
while (true) {
String line = reader.readLine();
if (line == null) {
break;
String[] listElement = line.split(",");
System.out.println(Arrays.toString(listElement));
// add to csvList
}
}
}
The output when I print listElement:
[>Shop A]
[shirt, 325]
[jeans, 475]
[>Shop B]
[car, 2]
[phone, 120]
[charger, 250]
If you want to ignore the shop name, then a simple parser will do:
Map<String, Integer> map = new HashMap<>();
String line;
String currentShop = null;
while ((line = reader.readLine()) != null) {
if (!line.matches(">.*,")) {
String[] listElement = line.split(",");
map.put(listElement[0], Integer.parseInt(listElement[1]));
}
}
The logic here is that if we encounter a shop line, indicated by > followed by a shop name and comma, then we don't try to parse that line into the map. Also, I assume that the separator for the data lines is really just commas, and no whitespace. If you expect whitespace, then you could split on something like \s*,\s* instead.
The code you've mentioned parses the line correctly. All you have to do now is insert those items into the created hashmap.
if(line.charAt(0)!='>')
{
int quantity = Integer.parseInt(listElement[1].trim());
String item = listElement[0].trim();
csvList.put( item , quantity);
}
Also, you might want to add another Map to store the shop names if required. The above code just ignores the shop information.
Related
-Java- I have a text file in which I am storing ID number, First Name, and Last Name on each line. I'm using BufferedReader to display the text files line by line. However I then need to take the ID number only from each line and store it into an array. If anyone can help it would be greatly appreciated.
As you said, you are already printing the line read from file, next you just need to split the line with the delimiter you have in file. Assuming you have comma as the delimiter, all you need to do is, split the line with comma and access the first element and store it in the List,
Here is the sample code,
public static void main(String[] args) throws Exception {
try(BufferedReader br = new BufferedReader(new FileReader("filename.txt"))) {
String line = null;
List<String> idList = new ArrayList<String>();
while((line = br.readLine()) != null) {
System.out.println(line); // you already printing it
String[] tokens = line.split("\\s*,\\s*"); // assuming your line is like this --> 123, Pushpesh, Rajwanshi
if (tokens.length > 0) {
idList.add(tokens[0]); // ID will be accessed at zero index
}
}
idList.forEach(System.out::println);
}
}
Using Java8 and above, you can do it in one liner.
List<String> idList = Files.lines(Paths.get("filename.txt")).filter(x -> x.trim().length() > 0)
.map(x -> x.split("\\s*,\\s*")).map(x -> x[0]).collect(Collectors.toList());
idList.forEach(System.out::println);
List<String> idList = Files.readAllLines(
Paths.get(FILE_PATH),
Charset.defaultCharset()
).stream()
.map(line -> line.split(SEPARATOR)[DATA_INDEX])
.collect(Collectors.toList());
FILE_PATH = file location ("c://users//..").
SEPARATOR = which separate datas (1:NAME:LAST_NAME < the separator for this ex = ":").
DATA_INDEX = index of data (1:NAME:LAST_NAME < the id index for this ex = 0).
I am reading a txt file and store the data in a hashtable, but I couldn't get the correct output. the txt file like this (part) attached image
this is part of my data
And I want to store the column 1 and column 2 as the key(String type) in hashtable, and column 3 and column 4 as the value (ArrayList type) in hashtable.
My code below:
private Hashtable<String, ArrayList<String[]>> readData() throws Exception {
BufferedReader br = new BufferedReader (new FileReader("MyGridWorld.txt"));
br.readLine();
ArrayList<String[]> value = new ArrayList<String[]>();
String[] probDes = new String[2];
String key = "";
//read file line by line
String line = null;
while ((line = br.readLine()) != null && !line.equals(";;")) {
//System.out.println("line ="+line);
String source;
String action;
//split by tab
String [] splited = line.split("\\t");
source = splited[0];
action = splited[1];
key = source+","+action;
probDes[0] = splited[2];
probDes[1] = splited[3];
value.add(probDes);
hashTableForWorld.put(key, value);
System.out.println("hash table is like this:" +hashTableForWorld);
}
br.close();
return hashTableForWorld;
}
The output looks like this:
it's a very long long line
I think maybe the hashtable is broken, but I don't know why. Thank you for reading my problem.
The first thing we need to establish is that you have a really obvious XY-Problem, in that "what you need to do" and "how you're trying to solve it" are completely at odds with each other.
So let's go back to the original problem and try to work out what we need first.
As best as I can determine, source and action are connected, in that they represent queryable "keys" to your data structure, and probability, destination, and reward are queryable "outcomes" in your data structure. So we'll start by creating objects to represent those two concepts:
public class SourceAction implements Comparable<SourceAction>{
public final String source;
public final String action;
public SourceAction() {
this("", "");
}
public SourceAction(String source, String action) {
this.source = source;
this.action = action;
}
public int compareTo(SourceAction sa) {
int comp = source.compareTo(sa.source);
if(comp != 0) return comp;
return action.compareto(sa.action);
}
public boolean equals(SourceAction sa) {
return source.equals(sa.source) && action.equals(sa.action);
}
public String toString() {
return source + ',' + action;
}
}
public class Outcome {
public String probability; //You can use double if you've written code to parse the probability
public String destination;
public String reward; //you can use double if you're written code to parse the reward
public Outcome() {
this("", "", "");
}
public Outcome(String probability, String destination, String reward) {
this.probability = probability;
this.destination = destination;
this.reward = reward;
}
public boolean equals(Outcome o) {
return probability.equals(o.probability) && destination.equals(o.destination) && reward.equals(o.reward);
public String toString() {
return probability + ',' + destination + ',' + reward;
}
}
So then, given these objects, what sort of Data Structure can properly encapsulate the relationship between these objects, given that a SourceAction seems to have a One-To-Many relationship to Outcome objects? My suggestion is that a Map<SourceAction, List<Outcome>> represents this relationship.
private Map<SourceAction, List<Outcome>> readData() throws Exception {
It is possible to use a Hash Table (in this case, HashMap) to contain these objects, but I'm trying to keep the code as simple as possible, so we're going to stick to the more generic interface.
Then, we can reuse the logic you used in your original code to insert values into this data structure, with a few tweaks.
private Map<SourceAction, List<Outcome>> readData() {
//We're using a try-with-resources block to eliminate the later call to close the reader
try (BufferedReader br = new BufferedReader (new FileReader("MyGridWorld.txt"))) {
br.readLine();//Skip the first line because it's just a header
//I'm using a TreeMap because that makes the implementation simpler. If you absolutely
//need to use a HashMap, then make sure you implement a hash() function for SourceAction
Map<SourceAction, List<Outcome>> dataStructure = new TreeMap<>();
//read file line by line
String line = null;
while ((line = br.readLine()) != null && !line.equals(";;")) {
//split by tab
String [] splited = line.split("\\t");
SourceAction sourceAction = new SourceAction(splited[0], splited[1]);
Outcome outcome = new Outcome(splited[2], splited[3], splited[4]);
if(dataStructure.contains(sourceAction)) {
//Entry already found; we're just going to add this outcome to the already
//existing list.
dataStructure.get(sourceAction).add(outcome);
} else {
List<Outcome> outcomes = new ArrayList<>();
outcomes.add(outcome);
dataStructure.put(sourceAction, outcomes);
}
}
} catch (IOException e) {//Do whatever, or rethrow the exception}
return dataStructure;
}
Then, if you want to query for all the outcomes associated with a given source + action, you need only construct a SourceAction object and query the Map for it.
Map<SourceAction, List<Outcome>> actionMap = readData();
List<Outcome> outcomes = actionMap.get(new SourceAction("(1,1)", "Up"));
assert(outcomes != null);
assert(outcomes.size() == 3);
assert(outcomes.get(0).equals(new Outcome("0.8", "(1,2)", "-0.04")));
assert(outcomes.get(1).equals(new Outcome("0.1", "(2,1)", "-0.04")));
assert(outcomes.get(2).equals(new Outcome("0.1", "(1,1)", "-0.04")));
This should yield the functionality you need for your problem.
You should change your logic for adding to your hashtable to check for the key you create. If the key exists, then grab your array list of arrays that it maps to and add your array to it. Currently you will overwrite the data.
Try this
if(hashTableForWorld.containsKey(key))
{
value = hashTableForWorld.get(key);
value.add(probDes);
hashTableForWorld.put(key, value);
}
else
{
value = new ArrayList<String[]>();
value.add(probDes);
hashTableForWorld.put(key, value);
}
Then to print the contents try something like this
for (Map.Entry<String, ArrayList<String[]>> entry : hashTableForWorld.entrySet()) {
String key = entry.getKey();
ArrayList<String[]> value = entry.getValue();
System.out.println ("Key: " + key + " Value: ");
for(int i = 0; i < value.size(); i++)
{
System.out.print("Array " + i + ": ");
for(String val : value.get(i))
System.out.print(val + " :: ")
System.out.println();
}
}
Hashtable and ArrayList (and other collections) do not make a copy of key and value, and thus all values you are storing are the same probDes array you are allocating at the beginning (note that it is normal that the String[] appears in a cryptic form, you would have to make it pretty yourself, but you can still see that it is the very same cryptic thing all the time).
What is sure is that you should allocate a new probDes for each element inside the loop.
Based on your data you could work with an array as value in my opinion, there is no real use for the ArrayList
And the same applies to value, it has to be allocated separately upon encountering a new key:
private Hashtable<String, ArrayList<String[]>> readData() throws Exception {
try(BufferedReader br=new BufferedReader(new FileReader("MyGridWorld.txt"))) {
br.readLine();
Hashtable<String, ArrayList<String[]>> hashTableForWorld=new Hashtable<>();
//read file line by line
String line = null;
while ((line = br.readLine()) != null && !line.equals(";;")) {
//System.out.println("line ="+line);
String source;
String action;
//split by tab
String[] split = line.split("\\t");
source = split[0];
action = split[1];
String key = source+","+action;
String[] probDesRew = new String[3];
probDesRew[0] = split[2];
probDesRew[1] = split[3];
probDesRew[2] = split[4];
ArrayList<String[]> value = hashTableForWorld.get(key);
if(value == null){
value = new ArrayList<>();
hashTableForWorld.put(key, value);
}
value.add(probDesRew);
}
return hashTableForWorld;
}
}
Besides relocating the variables to their place of actual usage, the return value is also created locally, and the reader is wrapped into a try-with-resource construct which ensures that it is getting closed even if an exception occurs (see official tutorial here).
I have contents in CSV file like this
User1,What is your favorite color?,color
User1,What is the name of your pet?,pet
User1,What is your mother's maiden name?,mother
User2,In what city were you born?,city
User2,What elementary school did you attend?,school
User2,What was your first best friend's name?,friend
I need to call OIM API which will take parameters like this
void setUserChallengeValues(java.lang.String userID,
boolean isUserLogin,
java.util.HashMap quesAnsMap)
where quesAnsMap parameter means HashMap of challenge question and answers
What is the efficient way of parsing the CSV file with hashmap of userid as key and question and answer as value?
My hashmap should be like User1 is key and value should have question as key and answer as value.
Any sample snippet to refer?
Thanks
Read the file line by line, spliting it by ',' using String.split()
HashMap<String, Map<String, String>> userAnswers = new HashMap<>();
BufferedReader reader = new BufferedReader(new FileReader("/PATH/TO/YOUR/FILE.cvs"));
String ln;
while((ln = reader.readLine()) != null)
{
String [] split = ln.split(",");
String user = split[0];
Map<String, String> userMap = userAnswers.get(user);
if(userMap == null)
{
userMap = new HashMap<String, String>();
userAnswers.put(user, userMap);
}
userMap.put(split[1], split[2]);
}
reader.close();
Here I am writing an method in which you can provide file (.csv) name as an parameter and get HashMap<String, String> as a Result
public Map<String, String> putYourCSVToHashMap(String prm_csvFile) {
BufferedReader br = null; //bufferReader
String line = "";
HashMap<String,Map<String, String>> hMapData = new HashMap<>();
Map<String, String> userMap; //refering to inner Hashmap.
String cvsSplitBy = ","; //parameter on which your csv lines is splitted as an Array.
try {
br = new BufferedReader(new FileReader(prm_csvFile)); // Read Your File and Stored into BufferedReader.
while ((line = br.readLine()) != null) { //read each Line of File till last.
String[] csv_LineAsArray= line.split(cvsSplitBy); //each line will is splitted into an String Array.
String username = csv_LineAsArray[0]; //pick username available at 0th Index.
userMap= hMapData.get(username);
if(userMap == null) //if perticular user doesnot have any record
{
//Create a New Object for each new line where Question as a key Answer as a Value.
userMap = new HashMap<String, String>();
hMapData.put(user, userMap);
}
// put question as a key and Answer as a Value.
userMap.put(csv_LineAsArray[1], csv_LineAsArray[2]);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return hMapData; // return your csv file as a HashMap.
}
I will tell you how I would do it, following the principle "Keep it as simple as possible".
I have read the other answers and I think using String.split is bad idea since you know exactly where to look for your values in each line of the CSV file.
Much better approach would be to use substring.
So here is sort of complete solution.
We create the class Tuple to store Q/A tuple. ( I am no using map since its a overkill :) )
class Tuple {
public String question;
public String answer;
public Tuple(String question, String answer) {
this.question = question;
this.answer = answer;
}
}
Its a simple class but it will save you lots of code later.
Now for the main class to do all the work.
class Questions {
private final Map csvData;
public Questions() {
csvData = new HashMap<String, Tuple>();
}
public void setUserChallengeValues(String line) {
String name = "";
String question = "";
String answer = "";
name = line.substring(0, line.indexOf(","));
line = line.substring(line.indexOf(",") + 1);
question = line.substring(0, line.indexOf(","));
line = line.substring(line.indexOf(",") + 1);
answer = line;
this.csvData.put(name, new Tuple(question, answer));
}
}
There is your method, the logic is very simple (a lot simpler compared to split in my opinion). You just look for ","'s index.
That way you can easily extract Name, Question and Answer from each line.
And finally the actual parsing becomes few lines of code.
Questions questions = new Questions();
//Feed the lines here one by one
String line1 = "User1,What is your favorite color?,color";
questions.setUserChallengeValues(line1);
Let me know if you need the whole code snippet.
Good luck :)
I have a file text called messages.txt as following:
6107586533 44335557075557777
4848675309 53366 6699044404666804448
6107584096 94466602777330999666887770223377778077778 883 336687777
First column represents the numbers of recipient and second column represents the digit-coded message(and I will use a decoder method to decode the second column digits, which I have already created).I used the following method to read the file text:
public void readMessagesFromFile() throws Exception{
BufferedReader in = new BufferedReader(new FileReader("messages.txt"));
String str;
List<String> list = new ArrayList<String>();
while((str = in.readLine()) != null){
list.add(str);
}
String[] stringArr = list.toArray(new String[3]);
for (String x: stringArr) {
System.out.print(x);
}
}
However, it stores everything(as it should be) like the following:
6107586533 443355570755577774848675309 53366 66990444046668044486107584096 94466602777330999666887770223377778077778 883 336687777
How can I read and store only the following portion:
44335557075557777
53366 6699044404666804448
94466602777330999666887770223377778077778 883 336687777
I want to read and store as in lines,i.e. each row in the second column will be assigned to each index of the array), just want to exclude the first column when I store the second column.
This will split the line and keep everything after the first token
List<String> list = new ArrayList<String>();
while((str = in.readLine()) != null){
String[] temp = str.trim().split("\\s+",2);
list.add(temp[1]);
}
The call to trim is in case there are leading blanks.
As to the conversion to an array your code, you don't need it, you can iterate over the list.
for (String s : list)
{
System.out.println(s);
}
Here is the link which states the reading of data from csv to Hashmap.
Convert CSV values to a HashMap key value pairs in JAVA
However, I am trying to read a file of csv, in which there are multiple values for a given key.
Eg:
Key - Value
Fruit - Apple
Fruit -Strawberry
Fruit -Grapefruit
Vegetable -Potatoe
Vegetable -Celery
where , Fruit and Vegetable are the keys.
I am using an ArrayList<> to store the values.
The code I am writing is able to store the keys , but stores only the last corresponding value .
So, when I print the hashmap , what I get is : Fruit - [Grapefruit] Vegetable- [Celery]
How can I iterate through the loop, and store all the values?
Following is the code, which I have written :
public class CsvValueReader {
public static void main(String[] args) throws IOException {
Map<String, ArrayList<String>> mp=null;
try {
String csvFile = "test.csv";
//create BufferedReader to read csv file
BufferedReader br = new BufferedReader(new FileReader(csvFile));
String line = "";
StringTokenizer st = null;
mp= new HashMap<String, ArrayList<String>>();
int lineNumber = 0;
int tokenNumber = 0;
//read comma separated file line by line
while ((line = br.readLine()) != null) {
lineNumber++;
//use comma as token separator
st = new StringTokenizer(line, ",");
while (st.hasMoreTokens()) {
tokenNumber++;
String token_lhs=st.nextToken();
String token_rhs= st.nextToken();
ArrayList<String> arrVal = new ArrayList<String>();
arrVal.add(token_rhs);
mp.put(token_lhs,arrVal);
}
}
System.out.println("Final Hashmap is : "+mp);
} catch (Exception e) {
System.err.println("CSV file cannot be read : " + e);
}
}
}
Currently, you're putting a new ArrayList in your map for each value you find. This replaces the old list you had for that particular key. Instead, you should use the existing array list (if it is already there), and add your value to it.
You should therefore replace this:
ArrayList<String> arrVal = new ArrayList<String>();
arrVal.add(token_rhs);
mp.put(token_lhs,arrVal);
By this:
ArrayList<String> arrVal = mp.get(token_lhs);
if (arrVal == null) {
arrVal = new ArrayList<String>();
mp.put(token_lhs,arrVal);
}
arrVal.add(token_rhs);
you have:
while readline
while splitline
new ArrayList(); and list.add()
map.put(key, arraylist)
so everytime you executed the map.put(), a new arrayList would be put into the map, and the value of existing key would be overwritten with the new arraylist. You need first get the arrayList from the map, with certain key, and append the value to the arraylist. if key doesn't exist, create a new arrayList.
If you want to save that part of work, you could consider to use some MultiMap api, E.g guava ArrayListMultiMap
This is because you create a new arrVal list every time.
You should try this code
ArrayList<String> arrVal = mp.get(token_lhs);
if(arrVal == null) {
arrVal = new ArrayList<String>();
mp.put(token_lhs, arrVal);
}
arrVal.add(token_rhs);
It seems that you always initalize a new ArrayList inside your while (st.hasMoreTokens()) loop, so you will only have the last ArrayList used (containing only the last token of the csv line)