I have a code snippet that is not sorting correctly. I need to sort a HashMap by keys using TreeMap, then write out to a text file. I have looked online on sorting and found that TreeMap can sort a HashMap by keys but I am not sure if I am utilizing it incorrectly. Can someone please take a look at the code snippet and advise if this is incorrect?
public void compareDICOMSets() throws IOException
{
FileWriter fs;
BufferedWriter bw;
fs = new FileWriter("dicomTagResults.txt");
bw = new BufferedWriter(fs);
Map<String, String> sortedMap = new TreeMap<String, String>();
for (Entry<String, String> entry : dicomFile.entrySet())
{
String s = entry.toString().substring(0, Math.min(entry.toString().length(), 11));
if(dicomTagList.containsKey(entry.getKey()))
{
sortedMap.put(s, entry.getValue());
Result.put(s, entry.getValue());
bw.write(s + entry.getValue() + "\r\n");
}
}
bw.close();
menu.showMenu();
}
}
UPDATE:
This is what I get for results when I do a println:
(0008,0080)
(0008,0092)
(0008,1010)
(0010,4000)
(0010,0010)
(0010,1030)
(0008,103E)
(0008,2111)
(0008,1050)
(0012,0040)
(0008,0094)
(0010,1001)
I am looking to sort this numerically. I have added String s to trim the Key down just to the tags as it was displaying a whole string of stuff that was unnecessary.
You should first order your results, and then print them.
For Java 8:
Map<String, String> Result = ...;
// This orders your Result map by key, using String natural order
Map<String, String> ordered = new TreeMap<>(Result);
// Now write the results
BufferedWriter bw = new BufferedWriter(new FileWriter("dicomTagResults.txt"));
ordered.forEach((k, v) -> bw.write(k + v + "\r\n");
bw.close();
For pre Java 8:
Map<String, String> Result = ...;
// This orders your Result map by key, using String natural order
Map<String, String> ordered = new TreeMap<>(Result);
// Now write the results
BufferedWriter bw = new BufferedWriter(new FileWriter("dicomTagResults.txt"));
for (Map.Entry<String, String> entry : ordered.entrySet()) {
String k = entry.getKey();
String v = entry.getValue();
bw.write(k + v + "\r\n");
}
bw.close();
Related
I am trying to sort a nested HashMap,
HashMap<Integer, HashMap<Integer, String>> myMap = new HashMap<>(), by a specific value in the inner HashMap.
The program reads a delimited file that contains the following values:
000001014|A||Harvey|T|Dent|05/27/1991|0902|000001014|05/27/1991|01/01/3000|
000001388|A||Tony|K|Stark|09/19/1992|0054|000001388|09/19/1992|01/01/3000|
000001395|A||Steve|C|Rogers|10/26/1992|7402|000001395|10/26/1992|01/01/3000| 000001396|A||Peter|P|Parker|11/02/1992|1002|000001396|11/02/1992|01/01/3000| 000011148|I||Drax|T|Destroyer|02/17/1992|7005|000011148|02/17/1992|01/01/3000| 000011141|A||Rocket|M|Raccoon|02/10/1992|7170|000011141|02/10/1992|01/01/3000|000001404|A||Natasha||Romanoff|12/28/1992|7240|00001404|12/28/1992|01/01/3000| 000001442|A||Bruce|T|Banner|10/06/1993|7012|000001442|10/06/1993|01/01/3000|
000001450|A||Scott|L|Lang|11/29/1993|0002|000001450|11/29/1993|01/01/3000| 000001486|A||Thor|J|Odinson|07/04/1994|0002|000001486|07/04/1994|01/01/3000|
I chose a Nested HashMap so that each line in the file has its own key and then each element in each line has a key. For example myMap.get(0).get(7) returns 0902, myMap.get(1).get(7) returns 0054, myMap.get(2).get(7) returns 7402. But the problem is that sorting the HashMap by the nested HashMap value has been a real humdinger. So, what I am trying to accomplish is to sort the whole HashMap by the 7th element in the inner map.
Should I sort myMap the old fashion way using a nested loops and binary sort or insertion sort? How do I tackle this problem?
private static Path directory() {
File home = FileSystemView.getFileSystemView().getHomeDirectory();
String path = home.getAbsolutePath();
Path dir;
//For reference Directory
C:\Users\PC_USER_NAME\Desktop\Work\Person\Employees.txt
if(getProperty("os.name").startsWith("Windows")) {//specify your
directory Windows
dir = Paths.get(path + File.separator + "Work" + File.separator + "Person");
} else {//Specify your directory Mac
dir = Paths.get(File.separator + "Users" + File.separator +
getProperty("user.name") + File.separator + "Desktop" + File.separator + "Work" + File.separator + "Person");
}
return dir;
}
private static void readFile() {
HashMap<Integer, HashMap<Integer, String>> myMap = new HashMap<>();
HashMap<Integer, String> inner = new HashMap<>();
BufferedReader reader;
String line;
int count = 0;
try {
File dir = new File(directory().toString());
File[] files = dir.listFiles((File pathname) ->
pathname.getName().startsWith("Employees"));
File lastModifiedFile = files[0];
for (File file : files) {
if (lastModifiedFile.lastModified() < file.lastModified()) {
lastModifiedFile = file;
}
}
reader = new BufferedReader(new FileReader(lastModifiedFile));
//Skips the header.
reader.readLine();
while((line = reader.readLine()) != null) {
String[] keyValue = line.split("\\|");
for (int i = 0; i < keyValue.length; i++) {
inner.put(i, keyValue[i]);
}
myMap.put(count, inner);
count++;
inner = new HashMap<>();
}
reader.close();
} catch (IOException e) { e.printStackTrace(); }
sort(myMap);
}
private static void sort(HashMap<Integer, HashMap<Integer, String>> myMap) {
Set<Entry<Integer, HashMap<Integer, String>>> sorted =
myMap.entrySet();
for(Entry<Integer, HashMap<Integer, String>> entry : sorted) {
System.out.println(entry.getKey() + " ==> " + entry.getValue().get(7));
}
//Won't add this method code for brevity sake
writeFile();
}
First of all - what does it mean to sort a HashMap? To print sorted values as I guess what does mean you won't be sorting Map itself, but some kind of collection of it's values
Second thing - why do you want to keep such data in a Map? It sounds like really bad idea, and you just spotted the first argument why
For me you should create some kind of Row class like
public class Row {
private List<String> items; // for '|' splitted values in a row, maybe it should be even String[]?
...
}
and keep your whole file as a List<Row>. Then you can create your own Comparator or even make Row implements Comparable
public class Row implements Comparable<Row>{
private List<String> items = new ArrayList<>();
...
#Override
public int compareTo(Row that) {
return this.items.get(8).compareTo(that.items.get(7));
}
}
Now you can easily sort the file using Collections.sort() util
Please notice that implementing Comparator allow you to create many versions of them (like SortBy6thComparator, SortBy7thComparator, SortBy8thComparator...). You just need to use then another version of sort method:
public static <T> void sort(List<T> list, Comparator<? super T> c)
****text file format:****
FirstName,lastname,role,startdate,emptype
sreedhar,reddy,Admin,20-2-2018,contract
shekar,kumar,Admin,20-2-2018,contract
RAJ,roy,Admin,20-2-2018,contract
somu,reddy,Admin,20-2-2018,contract
sumanth,reddy,Admin,20-2-2018,contract
Question:
How to read the text file and how to put in Map (Key ,vaule);
first line has key in map (ex: firstname,lastname,ect)
Second line on onwards value in map(eg:sreedhar,reddy,ect)
Map output:{Firstname:sreedhar,Lastname:reddy,role:Admin,startdat:2-6-2018}
please any one provide java code read the text file and put into map read has key, value pair.
You'll need to specify a different key for the Map as it requires a unique one each time:
A map cannot contain duplicate keys; each key can map to at most one
value.
So you're more than likely going to need a Map of Maps here:
Read in the file:
File file = new File("\\\\share\\path\\to\\file\\text.txt");
Add to scanner:
Scanner input = new Scanner(file);
Read the first line as your "header":
String[] headerArray = input.nextLine().split(",");
Create a Map of Maps:
Map<String, Map<String, String>> myMap = new HashMap<>();
Loop through the rest of the text file, adding to a Map, then adding that Map to the main Map, along with a key (I've used User0, User1...):
int pos = 0;
String user = "User";
while (input.hasNextLine()) {
Map<String, String> map = new HashMap<>();
int loop = 0;
String[] temp = input.nextLine().split(",");
for (String temp1 : temp) {
map.put(headerArray[loop], temp1);
loop++;
}
myMap.put(user + " " + pos, map);
pos++;
}
Once you break it down into steps, it makes life easier.
You can do something like this -
br = new BufferedReader(new FileReader("file.txt"));
String line = br.readLine();
String headerLine = line;
List<String> headerList = Arrays.asList(headerLine.split(","));
List<List<String>> valueListList = new ArrayList<List<String>>();
while (line != null) {
line = br.readLine();
String valueLine = line;
if(valueLine != null) {
List<String> valueList = Arrays.asList(valueLine.split(","));
valueListList.add(valueList);
}
}
Map<String, List<String>> map = new HashMap<String, List<String>>();
for(int i=0; i<headerList.size();i++){
List<String> tempList = new ArrayList<String>();
for(int j=0; j<headerList.size();j++){
tempList.add(valueListList.get(i).get(i));
}
map.put(headerList.get(i), tempList);
}
System.out.println(map);
Output:
{emptype=[contract, contract, contract, contract, contract],
startdate=[20-2-2018, 20-2-2018, 20-2-2018, 20-2-2018, 20-2-2018],
role=[Admin, Admin, Admin, Admin, Admin],
lastname=[kumar, kumar, kumar, kumar, kumar],
FirstName=[sreedhar, sreedhar, sreedhar, sreedhar, sreedhar]}
The question below is in Java
Sample data : https://tartarus.org/martin/PorterStemmer/output.txt
I have a tokenizationString String array that contain words that similar to the list above with many duplicated words.
I have to conver that string array into a hashmap and then use the hashmap to count the number of times each word is used (count the duplicated value in the string array but i have to use hashmap related method) .
I am thinking of doing in this way
Map<Integer, String> hashMap = new HashMap<Integer, String>();
for(int i = 0 ; i < tokenizationString.length; i++)
{
hashMap.put(i, tokenizationString[i]);
}
After that I will have to sort the string array by # of time they are used.
In the end I want to be able to print out the result like:
the "was used" 502 "times"
i "was used" 50342 "times"
apple "was used" 50 "times"
Firstly, your map should be like Map<String, Integer>(string and its frequency).
I am giving you the Java 8 stream solution.
public static void main(String[] args) {
try (Stream<String> lines = Files.lines(Paths.get("out.txt"))) {
Map<String, Long> frequency = lines
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet()
.stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(o, n) -> o,
LinkedHashMap::new
));
} catch (IOException e) {
e.printStackTrace();
}
}
Above code will read from file line by line. Then collect as a frequency map. Then again convert them into stream of entrySet. Then sort the stream based on the value in reverse order. Lastly collect them as a LinkedHashMap. LinkedHashMap because it will maintain the insersion order. Take look at Java 8 Stream API.
Instead of
hashMap.put(i, tokenizationString[i]);
first check if the word is already present, and then increment the corresponding entry:
int count = hashMap.containsKey(tokenizationString[i]) ? hashMap.get(tokenizationString[i]) : 0;
hashMap.put(tokenizationString[i], count + 1);
you can achieve this by Google Gauva library's MultiMap class as below. Also find the working example at this link - https://gist.github.com/dkalawadia/8d06fba1c2c87dd94ab3e803dff619b0
FileInputStream fstream = null;
BufferedReader br = null;
try {
fstream = new FileInputStream("C:\\temp\\output.txt");
br = new BufferedReader(new InputStreamReader(fstream));
String strLine;
Multimap<String, String> multimap = ArrayListMultimap.create();
// Read File Line By Line
while ((strLine = br.readLine()) != null) {
multimap.put(strLine, strLine);
}
for (String key : multimap.keySet()) {
System.out.println(key + "was used " + multimap.get(key).size() + "times");
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fstream != null) {
fstream.close();
}
if(br!=null){
br.close();
}
}
I'm new to Java and I would like to read this file content using Java:
Filename Type Size Used Priority
/dev/mapper/VolGroup00-LogVol01 partition 524280 0 -1
/dev/mapper/VolGroup00-LogVol02 partition 324280 0 -1
Can you show me some working example with Java 8?
This is the code so far:
private static HashMap<String, HashMap<String, Long>> totalSwap() throws FileNotFoundException, IOException
{
File file = new File("/proc/swaps");
if (!file.exists())
{
System.err.println("/proc/swaps did not exist!");
return null;
}
else if (file.isDirectory())
{
System.err.println("/proc/swaps is a directory, not a file.");
return null;
}
Pattern pattern = Pattern.compile("([\\/A-Za-z0-9]+)[\\s]+([a-z]+)[\\s]+([0-9]+)[\\s]+([0-9]+)[\\s]+([\\-0-9]+).*");
BufferedReader reader = new BufferedReader(new FileReader("/proc/swaps"));
String s = reader.readLine();
while (s != null)
{
Matcher matcher = pattern.matcher(s);
if (matcher.matches())
{
HashMap<String, Long> usageData2 = new HashMap<>();
usageData2.put("allSwap", Long.parseLong(matcher.group(3)));
usageData2.put("utilizedSwap", Long.parseLong(matcher.group(4)));
data.put("First", usageData2);
}
s = reader.readLine();
}
reader.close();
return data;
}
I don't know how to read the FileName column. Finally I would like to get this result:
HashMap</dev/mapper/VolGroup00-LogVol01, HashMap<Size, 524280>
HashMap<Used, 0>>
HashMap</dev/mapper/VolGroup00-LogVol02, HashMap<Size, 334220>
HashMap<Used, 0>>
Can you help to solve this problem?
It may be better to split using a tab delimeter, if i remember correctly, linux is outputting using the tab character.
I have had to improvise with youre code but it should be easy to plug your code back in.
See my example below:
private static HashMap<String, HashMap<String, Long>> totalSwap()
{
HashMap<String, HashMap<String, Long>> data = new HashMap<String, HashMap<String, Long>>();
Pattern pattern = Pattern.compile("([\\/A-Za-z0-9]+)[\\s]+[A-Za-z]+[\\s]+([0-9]+)[\\s]+([0-9]+)[\\s]+([\\-0-9]+).*");
String s = "/dev/mapper/VolGroup00-LogVol01\tpartition\t524280\t0\t-1\n/dev/mapper/VolGroup00-LogVol02\tpartition\t324280\t0\t-1";
String[] columns = s.split("\t");
for (String line : columns) {
HashMap<String, Long> usageData2 = new HashMap<>();
usageData2.put("allSwap", Long.parseLong(columns[2]));
usageData2.put("utilizedSwap", Long.parseLong(columns[3]));
data.put(columns[0], usageData2);
}
return data;
}
Maybe it would be better to use StringTokenizer with delimiter tab("\t") and retrieve required columns.
I put a key-value pair in a Java HashMap and converted it to a String using the toString() method.
Is it possible to convert this String representation back to a HashMap object and retrieve the value with its corresponding key?
Thanks
It will work if toString() contains all data needed to restore the object. For example it will work for map of strings (where string is used as key and value):
// create map
Map<String, String> map = new HashMap<String, String>();
// populate the map
// create string representation
String str = map.toString();
// use properties to restore the map
Properties props = new Properties();
props.load(new StringReader(str.substring(1, str.length() - 1).replace(", ", "\n")));
Map<String, String> map2 = new HashMap<String, String>();
for (Map.Entry<Object, Object> e : props.entrySet()) {
map2.put((String)e.getKey(), (String)e.getValue());
}
This works although I really do not understand why do you need this.
toString() approach relies on implementation of toString() and it can be lossy in most of the cases.
There cannot be non lossy solution here. but a better one would be to use Object serialization
serialize Object to String
private static String serialize(Serializable o) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(o);
oos.close();
return Base64.getEncoder().encodeToString(baos.toByteArray());
}
deserialize String back to Object
private static Object deserialize(String s) throws IOException,
ClassNotFoundException {
byte[] data = Base64.getDecoder().decode(s);
ObjectInputStream ois = new ObjectInputStream(
new ByteArrayInputStream(data));
Object o = ois.readObject();
ois.close();
return o;
}
Here if the user object has fields which are transient, they will be lost in the process.
old answer
Once you convert HashMap to String using toString(); It's not that you can convert back it to Hashmap from that String, Its just its String representation.
You can either pass the reference to HashMap to method or you can serialize it
Here is the description for toString() toString()
Here is the sample code with explanation for Serialization.
and to pass hashMap to method as arg.
public void sayHello(Map m){
}
//calling block
Map hm = new HashMap();
sayHello(hm);
you cannot do this directly but i did this in a crazy way as below...
The basic idea is that, 1st you need to convert HashMap String into Json then you can deserialize Json using Gson/Genson etc into HashMap again.
#SuppressWarnings("unchecked")
private HashMap<String, Object> toHashMap(String s) {
HashMap<String, Object> map = null;
try {
map = new Genson().deserialize(toJson(s), HashMap.class);
} catch (TransformationException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return map;
}
private String toJson(String s) {
s = s.substring(0, s.length()).replace("{", "{\"");
s = s.substring(0, s.length()).replace("}", "\"}");
s = s.substring(0, s.length()).replace(", ", "\", \"");
s = s.substring(0, s.length()).replace("=", "\":\"");
s = s.substring(0, s.length()).replace("\"[", "[");
s = s.substring(0, s.length()).replace("]\"", "]");
s = s.substring(0, s.length()).replace("}\", \"{", "}, {");
return s;
}
implementation...
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("Name", "Suleman");
map.put("Country", "Pakistan");
String s = map.toString();
HashMap<String, Object> newMap = toHashMap(s);
System.out.println(newMap);
i converted HashMap into an String
using toString() method and pass to
the another method that take an String
and convert this String into HashMap
object
This is a very, very bad way to pass around a HashMap.
It can theoretically work, but there's just way too much that can go wrong (and it will perform very badly). Obviously, in your case something does go wrong. We can't say what without seeing your code.
But a much better solution would be to change that "another method" so that it just takes a HashMap as parameter rather than a String representation of one.
You can make use of Google's "GSON" open-source Java library for this,
Example input (Map.toString) : {name=Bane, id=20}
To Insert again in to HashMap you can use below code:
yourMap = new Gson().fromJson(yourString, HashMap.class);
That's it Enjoy.
(In Jackson Library mapper It will produce exception "expecting double-quote to start field name")
What did you try?
objectOutputStream.writeObject(hashMap);
should work just fine, providing that all the objects in the hashMap implement Serializable.
You cannot revert back from string to an Object. So you will need to do this:
HashMap<K, V> map = new HashMap<K, V>();
//Write:
OutputStream os = new FileOutputStream(fileName.ser);
ObjectOutput oo = new ObjectOutputStream(os);
oo.writeObject(map);
oo.close();
//Read:
InputStream is = new FileInputStream(fileName.ser);
ObjectInput oi = new ObjectInputStream(is);
HashMap<K, V> newMap = oi.readObject();
oi.close();
Are you restricted to use only HashMap ??
Why can't it be so much flexible JSONObject you can do a lot with it.
You can convert String jsonString to JSONObject jsonObj
JSONObject jsonObj = new JSONObject(jsonString);
Iterator it = jsonObj.keys();
while(it.hasNext())
{
String key = it.next().toString();
String value = jsonObj.get(key).toString();
}
Using ByteStream can convert the String but it can encounter OutOfMemory exception in case of large Strings. Baeldung provides some nice solutions in his pot here : https://www.baeldung.com/java-map-to-string-conversion
Using StringBuilder :
public String convertWithIteration(Map<Integer, ?> map) {
StringBuilder mapAsString = new StringBuilder("{");
for (Integer key : map.keySet()) {
mapAsString.append(key + "=" + map.get(key) + ", ");
}
mapAsString.delete(mapAsString.length()-2, mapAsString.length()).append("}");
return mapAsString.toString(); }
Please note that lambdas are only available at language level 8 and above
Using Stream :
public String convertWithStream(Map<Integer, ?> map) {
String mapAsString = map.keySet().stream()
.map(key -> key + "=" + map.get(key))
.collect(Collectors.joining(", ", "{", "}"));
return mapAsString; }
Converting String Back to Map using Stream :
public Map<String, String> convertWithStream(String mapAsString) {
Map<String, String> map = Arrays.stream(mapAsString.split(","))
.map(entry -> entry.split("="))
.collect(Collectors.toMap(entry -> entry[0], entry -> entry[1]));
return map; }
I hope you actually need to get the value from string by passing the hashmap key. If that is the case, then we don't have to convert it back to Hashmap. Use following method and you will be able to get the value as if it was retrieved from Hashmap itself.
String string = hash.toString();
String result = getValueFromStringOfHashMap(string, "my_key");
/**
* To get a value from string of hashmap by passing key that existed in Hashmap before converting to String.
* Sample string: {fld_category=Principal category, test=test 1, fld_categoryID=1}
*
* #param string
* #param key
* #return value
*/
public static String getValueFromStringOfHashMap(String string, String key) {
int start_index = string.indexOf(key) + key.length() + 1;
int end_index = string.indexOf(",", start_index);
if (end_index == -1) { // because last key value pair doesn't have trailing comma (,)
end_index = string.indexOf("}");
}
String value = string.substring(start_index, end_index);
return value;
}
Does the job for me.
It is possible to rebuild a collection out of its string presentation but it will not work if the elements of the collection don't override their own toString method.
Therefore it's much safer and easier to use third party library like XStream which streams objects in human readable XML.
This may be inefficient and indirect. But
String mapString = "someMap.toString()";
new HashMap<>(net.sf.json.JSONObject.fromObject(mapString));
should work !!!