I am trying to create a method - 'ReadFile' that would return HashMap object. This object is created by reading an input file and each line of the file is parsed to get the key and value which will be used to create this HashMap object. The problem is when I try to refresh the StringBuffer object - 'value' in the code below. It looks like it wipes out the 'value' values in the HashMap - 'hm'. Any idea how I could effectively refresh - 'value' in the 'for' loop below? Also, I need to read 2 separate input files where the key values of each of these files will be exactly the same. Then I need to compare these to files based on the key and append the values from each to a third file or in an arraylist/vector (or the into hash?). Later I would be using certain field value to do some mathematical calculation and dump the outputs into a separate file. How would I be able to achieve this in the best possible way? The expected output file/array/vector along with the input files are given below. Any help would be much appreciated.
Thanks.
code: public static HashMap readFile(String file_name) {
Depending on the format of your data you could use the Properties.load() method to automatically convert an InputStream (file) into a Properties object (similar to a HashMap in many ways).
The method takes multiple formats for keys/values, so take a look at the API for Properties and see if this would work for you.
Your problem is that StringBuffers are mutable - you are always putting the same object into the map, so all the values will be the same.
If you replace
hm.put(key, value);
by
hm.put(key, value.toString());
you will put the current value of the StringBuffer into the map in the form of a new, immutable String object, which won't be changed later on.
Does that sound reasonable?
The soul is dyed the color of its thoughts. Think only on those things that are in line with your principles and can bear the light of day. The content of your character is your choice. Day by day, what you do is who you become. Your integrity is your destiny - it is the light that guides your way. - Heraclitus
Tariq Ahsan
Ranch Hand
Joined: Nov 03, 2003
Posts: 116
posted
0
Thanks Ilja for your reply. Well, changing to hm(key, value.toString()) unfortunately did not solve my problem. The values from other keys are getting appended. e.g.
But I guess I need to have the following instead in the 'hm' -
3, 123, abd, klm, 723, abx, olm
Tariq Ahsan
Ranch Hand
Joined: Nov 03, 2003
Posts: 116
posted
0
I am sorry Ilja I was totally wrong. It worked! I also commented out the value.setLength(0) while making the change to hm.put(key, value.toString()). Putting back value.setLength(0) and the change you suggested did the job. Any idea how I can get the about the other part of my question (comparing two hashes to create the third array/vector/hash) done?
Stepping back a little, having a map value which *looks* like a list or a set but is represented by a String or a StringBuffer doesn't sound object-oriented to me. Why not use a Set, a List or a user-defined class to hold your Map value?
There is no emoticon for what I am feeling!
Tariq Ahsan
Ranch Hand
Joined: Nov 03, 2003
Posts: 116
posted
0
I am not much familiar with Set or List. So what Jeff is suggesting is I could compare two Set's by the some sort of key from each of these and do the same what I want as I mentioned in my posting? If possible could you please show me a small code snippet how I can use Set or List for this matter?
Here is an example of taking two Maps with the Set values and the same key set, and doing a key-wise union of their values.
Tariq Ahsan
Ranch Hand
Joined: Nov 03, 2003
Posts: 116
posted
0
Sweet! Works like a charm. Thanks Jeff!!!
Tariq Ahsan
Ranch Hand
Joined: Nov 03, 2003
Posts: 116
posted
0
One last question. It looks like for every key the values from the other key's are getting appended. Do I need to refresh the Set object for value in some way?
What I mean is I am getting like for key 3 values 123, abd, klm,xyz, 000, 111,abc, cde, efg But expecting only 123, abd, klm
Thanks
Tariq Ahsan
Ranch Hand
Joined: Nov 03, 2003
Posts: 116
posted
0
One other thing forgot to mention the order of values of a key is very important for me. e.g. if the input file line has 1, abc, cde, efg the hash should have the 1 (key) and exactly abc, cde, efg (value).
Jeff Albertson
Ranch Hand
Joined: Sep 16, 2005
Posts: 1780
posted
0
Originally posted by Tariq Ahsan: One other thing forgot to mention the order of values [of a key] is very important for me. e.g. if the input file line has 1, abc, cde, efg the hash should have the 1 (key) and exactly abc, cde, efg (value).
Originally posted by Tariq Ahsan: One last question. It looks like for every key the values from the other key's are getting appended. Do I need to refresh the Set object for value in some way?
What I mean is I am getting like for key 3 values 123, abd, klm,xyz, 000, 111,abc, cde, efg But expecting only 123, abd, klm
Post some code. I think you are not creating separate Set objects for each entry -- that was an error you had in your original code.
Tariq Ahsan
Ranch Hand
Joined: Nov 03, 2003
Posts: 116
posted
0
Here's the code what I have now. I'll try out the LinkedHashSet as you suggested for retaining the order of the Set.
HashMap base_hash = readFile(basefile); HashMap input_hash = readFile(inputfile); Set entries = base_hash.entrySet(); for (Iterator it = entries.iterator(); it.hasNext(); ) { Map.Entry entry = (Map.Entry) it.next(); Set val = (Set) entry.getValue();
// loop through info to check for desired value val.containsAll((Set) input_hash.get(entry.getKey())); } System.out.println("Bash Hash : " + base_hash);
System.out.println("\n" + "You must specify the base file and a file name as argument" + "\n"); System.out.println("USAGE: java CompareFiles <BaseFileName> <InputFileName>" + "\n");
}
}
public static HashMap readFile(String file_name) {
List list = new ArrayList(); String line = reader.readLine(); while(line != null){ list.add(line); line = reader.readLine(); }
reader.close();
// Setting delimiter Pattern p = Pattern.compile(","); //StringBuffer val = new StringBuffer(); Set value = new HashSet();
// records are in the array one line per element // also, each was printed to stout as it was read Iterator iterator = list.iterator(); while(iterator.hasNext()){
String str = (String) iterator.next(); // Parsing each line by delimiter String[] result = p.split(str); // Storing the first value from the String array as the key String key = result[0]; // Rest of the String array will be the value for (int i=1; i<result.length; i++) { //val.append(result[i] + ','); value.add(result[i]); }
System.out.println("Key is " + key + " Value is " + value); hm.put(key, value); }
Key is 1 Value is [cde, abc, efg] Key is 2 Value is [ghi, lmn, cde, abc, jkl, efg] Key is 3 Value is [ghi, stw, nop, pqr, lmn, cde, abc, jkl, efg] ReadFile {3=[ghi, stw, nop, pqr, lmn, cde, abc, jkl, efg], 2=[ghi, stw, nop, pqr, lmn, cde, abc, jkl, efg], 1=[ghi, stw, nop, pqr, lmn, cde, abc, jkl, efg]} Key is 1 Value is [cde, 111, efg] Key is 2 Value is [222, lmn, cde, 111, jkl, efg] Key is 3 Value is [lmn, 222, 333, lmn, cde, stv, 111, jkl, efg] ReadFile {3=[lmn, 222, 333, lmn, cde, stv, 111, jkl, efg], 2=[lmn, 222, 333, lmn, cde, stv, 111, jkl, efg], 1=[lmn, 222, 333, lmn, cde, stv, 111, jkl, efg]} Bash Hash : {3=[ghi, stw, nop, pqr, lmn, cde, abc, jkl, efg], 2=[ghi, stw, nop, pqr, lmn, cde, abc, jkl, efg], 1=[ghi, stw, nop, pqr, lmn, cde, abc, jkl, efg]}
Thanks for all your help!
Tariq Ahsan
Ranch Hand
Joined: Nov 03, 2003
Posts: 116
posted
0
Looks like using LinkedHashSet instead of just the HashSet is working for me to maintain the order of the value text. Now I am left with finding the way to preventing values from other key's to get appended to a key value.
Thanks!
Tariq Ahsan
Ranch Hand
Joined: Nov 03, 2003
Posts: 116
posted
0
I got most of the code working. Except for using 'addAll' for the Set object only picks up the values that are not duplicate. Is there a way to ignore duplication and add the second set to the first one?
System.out.println("\n" + "You must specify the base file and a file name as argument" + "\n"); System.out.println("USAGE: java CompareFiles <BaseFileName> <InputFileName>" + "\n");
}
}
public static HashMap readFile(String file_name) {
List list = new ArrayList(); String line = reader.readLine(); while(line != null){ list.add(line); line = reader.readLine(); }
reader.close();
// Setting delimiter Pattern p = Pattern.compile(",");
// records are in the array one line per element // also, each was printed to stout as it was read Iterator iterator = list.iterator(); while(iterator.hasNext()){
String str = (String) iterator.next(); // Parsing each line by delimiter String[] result = p.split(str); // Storing the first value from the String array as the key String key = result[0]; Set value = new LinkedHashSet(); // Rest of the String array will be the value for (int i=1; i<result.length; i++) { value.add(result[i]); }
System.out.println("Key is " + key + " Value is " + value); hm.put(key, value); }
Key is 1 Value is [abc, cde, efg] Key is 2 Value is [ghi, jkl, lmn] Key is 3 Value is [nop, pqr, stw] ReadFile {3=[nop, pqr, stw], 2=[ghi, jkl, lmn], 1=[abc, cde, efg]} Key is 1 Value is [111, cde, efg] Key is 2 Value is [222, jkl, lmn] Key is 3 Value is [333, stv, lmn] ReadFile {3=[333, stv, lmn], 2=[222, jkl, lmn], 1=[111, cde, efg]} Base Hash: {3=[nop, pqr, stw], 2=[ghi, jkl, lmn], 1=[abc, cde, efg]} Input Hash: {3=[333, stv, lmn], 2=[222, jkl, lmn], 1=[111, cde, efg]} Base Hash : {3=[nop, pqr, stw, 333, stv, lmn], 2=[ghi, jkl, lmn, 222], 1=[abc, cde, efg, 111]}
Tariq Ahsan
Ranch Hand
Joined: Nov 03, 2003
Posts: 116
posted
0
I got most of the code working. Except for using 'addAll' for the Set object only picks up the values that are not duplicate. Is there a way to ignore duplication and add the second set to the first one?
System.out.println("\n" + "You must specify the base file and a file name as argument" + "\n"); System.out.println("USAGE: java CompareFiles <BaseFileName> <InputFileName>" + "\n");
}
}
public static HashMap readFile(String file_name) {
List list = new ArrayList(); String line = reader.readLine(); while(line != null){ list.add(line); line = reader.readLine(); }
reader.close();
// Setting delimiter Pattern p = Pattern.compile(",");
// records are in the array one line per element // also, each was printed to stout as it was read Iterator iterator = list.iterator(); while(iterator.hasNext()){
String str = (String) iterator.next(); // Parsing each line by delimiter String[] result = p.split(str); // Storing the first value from the String array as the key String key = result[0]; Set value = new LinkedHashSet(); // Rest of the String array will be the value for (int i=1; i<result.length; i++) { value.add(result[i]); }
System.out.println("Key is " + key + " Value is " + value); hm.put(key, value); }
Key is 1 Value is [abc, cde, efg] Key is 2 Value is [ghi, jkl, lmn] Key is 3 Value is [nop, pqr, stw] ReadFile {3=[nop, pqr, stw], 2=[ghi, jkl, lmn], 1=[abc, cde, efg]} Key is 1 Value is [111, cde, efg] Key is 2 Value is [222, jkl, lmn] Key is 3 Value is [333, stv, lmn] ReadFile {3=[333, stv, lmn], 2=[222, jkl, lmn], 1=[111, cde, efg]} Base Hash: {3=[nop, pqr, stw], 2=[ghi, jkl, lmn], 1=[abc, cde, efg]} Input Hash: {3=[333, stv, lmn], 2=[222, jkl, lmn], 1=[111, cde, efg]} Base Hash : {3=[nop, pqr, stw, 333, stv, lmn], 2=[ghi, jkl, lmn, 222], 1=[abc, cde, efg, 111]}
Jeff Albertson
Ranch Hand
Joined: Sep 16, 2005
Posts: 1780
posted
0
What do you mean by "Is there a way to ignore duplication and add the second set to the first one" Doesn't the semantics of Set mean that duplicates are ignored?
Tariq Ahsan
Ranch Hand
Joined: Nov 03, 2003
Posts: 116
posted
0
My mistake. I meant to say is there a way to retain duplication while adding one set to another?
Jeff Albertson
Ranch Hand
Joined: Sep 16, 2005
Posts: 1780
posted
0
Back in my post of December 20, 2005 06:40 PM, I asked if your values constituted a Set or a List, and I don't know if you pondered that further, but now it sounds like you need a list. So, change Set to List and change LinkedHashSet to ArrayList. [ December 21, 2005: Message edited by: Jeff Albrechtsen ]
System.out.println("\n" + "You must specify the base file and a file name as argument" + "\n"); System.out.println("USAGE: java CompareFiles <BaseFileName> <InputFileName>" + "\n");
}
}
public static HashMap readFile(String file_name) {
List list = new ArrayList(); String line = reader.readLine(); while(line != null){ list.add(line); line = reader.readLine(); }
reader.close();
// Setting delimiter Pattern p = Pattern.compile(",");
// records are in the array one line per element // also, each was printed to stout as it was read Iterator iterator = list.iterator(); while(iterator.hasNext()){
String str = (String) iterator.next(); // Parsing each line by delimiter String[] result = p.split(str); // Storing the first value from the String array as the key String key = result[0]; //Set value = new LinkedHashSet(); List value = new ArrayList(); // Rest of the String array will be the value for (int i=1; i<result.length; i++) { value.add(result[i]); }
Val : [1, nop, pqr, stw, 333, stv, lmn] Val : [2, ghi, jkl, lmn, 222, jkl, lmn] Val : [3, abc, cde, efg, 111, cde, efg]
The appended list from the second input file (input2) to the first file (input1) matched by key gets stored as a separate array list. Also like to have the 'key' in this list.