Right now, I'm trying to get this method of mine to print a .txt file of a HashMap that contains a word as a Key, and the number of times it appears in a read .txt file (done in another method) as a Value. The method needs to put the HashMap Keys in alphabetical order, and then print the corresponding Value next to it in a separate .txt file.
Here is my code for the method:
public static void writeVocabulary(HashMap<String, Integer> vocab, String fileName) {
// Converts the given HashMap keys (the words) into a List.
// Collections.sort() will sort the List of HashMap keys into alphabetical order.
List<String> listVal = new ArrayList<String>(vocab.keySet());
Collections.sort(listVal);
try
{
// Creating the writer
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(fileName)));
for (int i = 1; i < listVal.size(); i++) {
out.println(listVal.get(i) + " " + vocab.get(i));
}
out.close();
}
// Catching the file not found error
// and any other errors
catch (FileNotFoundException e) {
System.err.println(fileName + "cannot be found.");
}
catch (Exception e) {
System.err.println(e);
}
}
My problem is that, while a .txt file is printed, and the words are in perfect ASCII order (what I need), every value next to the word is returned null. I've tried many different ways of fixing this but to no avail. I think the problem is in my 'for' loop:
for (int i = 1; i < listVal.size(); i++) {
out.println(listVal.get(i) + " " + vocab.get(i));
}
I'm pretty sure my logic in this is faulty but I can't think of a solution. Any help would be much appreciated. Thanks in advance!
You need to use the correct map key to get the value from the map - this code currently uses the index in the List, not the value in the list (which is the actual key to the map).
for (int i = 0; i < listVal.size(); i++) {
out.println(listVal.get(i) + " " + vocab.get(listVal.get(i)));
}
And also start at index 0 if you want all the items (see initial condition in loop above). As suggested in a comment, you can alternatively use a TreeMap to iterate over the keys of the map in order
This is where an enhanced for loop would have kept you from making a mistake. You get values from a Map by using get(key):
for ( String key : listVal ) {
out.println( key + " " + vocab.get(key) );
}
You don't need to iterate through the list using the indexes; instead you can use:
for ( final String key : listVal ) {
out.println( key + " " + vocab.get( key ) );
}
and you can simplify things even further using a TreeSet to do the sorting:
for ( final String key : new TreeSet<String>( vocab.keySet() ) ) {
out.println( key + " " + vocab.get( key ) );
}
Related
Be gentle,
This is my first time using Apache Commons CSV 1.7.
I am creating a service to process some CSV inputs,
add some additional information from exterior sources,
then write out this CSV for ingestion into another system.
I store the information that I have gathered into a list of
HashMap<String, String> for each row of the final output csv.
The Hashmap contains the <ColumnName, Value for column>.
I have issues using the CSVPrinter to correctly assign the values of the HashMaps into the rows.
I can concatenate the values into a string with commas between the variables;
however,
this just inserts the whole string into the first column.
I cannot define or hardcode the headers since they are obtained from a config file and may change depending on which project uses the service.
Here is some of my code:
try (BufferedWriter writer = Files.newBufferedWriter(
Paths.get(OUTPUT + "/" + project + "/" + project + ".csv"));)
{
CSVPrinter csvPrinter = new CSVPrinter(writer,
CSVFormat.RFC4180.withFirstRecordAsHeader());
csvPrinter.printRecord(columnList);
for (HashMap<String, String> row : rowCollection)
{
//Need to map __record__ to column -> row.key, value -> row.value for whole map.
csvPrinter.printrecord(__record__);
}
csvPrinter.flush();
}
Thanks for your assistance.
You actually have multiple concerns with your technique;
How do you maintain column order?
How do you print the column names?
How do you print the column values?
Here are my suggestions.
Maintain column order.
Do not use HashMap,
because it is unordered.
Instead,
use LinkedHashMap which has a "predictable iteration order"
(i.e. maintains order).
Print column names.
Every row in your list contains the column names in the form of key values,
but you only print the column names as the first row of output.
The solution is to print the column names before you loop through the rows.
Get them from the first element of the list.
Print column values.
The "billal GHILAS" answer demonstrates a way to print the values of each row.
Here is some code:
try (BufferedWriter writer = Files.newBufferedWriter(
Paths.get(OUTPUT + "/" + project + "/" + project + ".csv"));)
{
CSVPrinter csvPrinter = new CSVPrinter(writer,
CSVFormat.RFC4180.withFirstRecordAsHeader());
// This assumes that the rowCollection will never be empty.
// An anonymous scope block just to limit the scope of the variable names.
{
HashMap<String, String> firstRow = rowCollection.get(0);
int valueIndex = 0;
String[] valueArray = new String[firstRow.size()];
for (String currentValue : firstRow.keySet())
{
valueArray[valueIndex++] = currentValue;
}
csvPrinter.printrecord(valueArray);
}
for (HashMap<String, String> row : rowCollection)
{
int valueIndex = 0;
String[] valueArray = new String[row.size()];
for (String currentValue : row.values())
{
valueArray[valueIndex++] = currentValue;
}
csvPrinter.printrecord(valueArray);
}
csvPrinter.flush();
}
for (HashMap<String,String> row : rowCollection) {
Object[] record = new Object[row.size()];
for (int i = 0; i < columnList.size(); i++) {
record[i] = row.get(columnList.get(i));
}
csvPrinter.printRecord(record);
}
The code looks like this:
for (int i = 0; i < fileList.size(); i++) {
System.out.println("File List size is " + fileList.size());
String fileName = (fileList.get(i).fileName);
String accountNumber = accountNumber(fileName);
System.out.println(accountNumber);
if(accountNumber.equals("fail")) {
decode(dirLocation+fileName,"C:/.../.../.../ChunkTestInvalid/"+fileName);
fileList.remove(i);
System.out.println("File removed at first stage: "+fileName);
}
else {..........
I'm trying to setup a situation where files that don't match criteria in the accountNumber method get decoded to a particular folder on my machine and removed from fileList, which is an ArrayList for a custom Object. The fileList.remove(i) call is removing SOMETHING from the ArrayList (as the fileList.size() value is decreasing) but it's removing something other the object located at fileList.get(i) at the start of the for loop, because it keeps returning the same object.
What is the correct way to identify that the object I want to remove from the ArrayList is the one that exists at fileList.get(i) at that time?
You can try using iterator like this -
List<String> fileList;
Iterator<String> iter = fileList.iterator();
while (iter.hasNext()) {
System.out.println("File List size is " + fileList.size());
String fileName = (iter.next().fileName);
String accountNumber = accountNumber(fileName);
System.out.println(accountNumber);
if(accountNumber.equals("fail")) {
decode(dirLocation+fileName,"C:/.../.../.../ChunkTestInvalid/"+fileName);
iter.remove();
System.out.println("File removed at first stage: "+fileName);
}
else {..........
}
This question already has answers here:
How to append text to an existing file in Java?
(31 answers)
Closed 6 years ago.
This code will iterate through a number of pages to find and extract elements on the page. Once the loop has completed it will generate a log file with these elements from a HashMap, but the results aren't being appended and are rather being overwritten.
int d = new Integer(0);
for (int i = 0; i <= 100; d += 10) {
String url = Constants.FilterUrl + "&startIndex=" + d;
this.getAuthors();
driver.get(url);
if (!driver.getPageSource().contains("h3")) break;
}
/* Send HashMap values to text file */
File file = new File(Constants.FILEPATH + Constants.dateFormat.format(new Date()) + ".txt");
try{
if(!file.exists()){
System.out.println("We had to make a new file.");
file.createNewFile();
}
PrintWriter out = new PrintWriter(new FileWriter(file), true);
map.forEach((k, v) -> out.println(k + ", " + v));
out.append("************** " + "\n");
out.close();
} catch(IOException e) {
System.out.println("COULD NOT LOG!!");
}
}
public void getAuthors(){
List<WebElement> allElements = driver.findElements(By.tagName("h3"));
/* Create HashMap and store H3 elements in the key set */
this.map = new HashMap<String, String>();
for (WebElement element1 : allElements) {
map.put(element1.getText(), element1.findElement(By.tagName("a")).getAttribute("href"));
}
/* Visit pages for H3 elements and retrieve names of the authors */
for (Map.Entry<String, String> entry : map.entrySet()) {
driver.get(entry.getValue());
entry.setValue(driver.findElement(By.className("userlink-0")).getText());
}
}
Any ideas?
map.put(element1.getText(),
element1.findElement(By.tagName("a")).getAttribute("href"));
If there is any entry in HashMap with the same text as element1.getText(), it will override it.
Also you are creating map for each call, it will create a new Map each time and lead to data loss for earlier content.
/* Create HashMap and store H3 elements in the key set */
this.map = new HashMap<String, String>();
You should create this at instance level.
For generating unique key, define a number variable at instance level and increment that for each put.
long counter = 0;
map.put(counter++, element1.findElement(By.tagName("a")).getAttribute("href"));
May be change the HashMap to take long as Key instead of String.
for (WebElement element1 : allElements) {
i++
map.put(element1.getText()+i, element1.findElement(By.tagName("a")).getAttribute("href"));
}
add i++ so it doesnt override
I am working on an Android application which uses Xerces for Iteration. I have a custom method which is called to store a filtered set of data values in it after being iterated through via a while loop. Part of the specific while loop is as follows:
while((n = iterator.nextNode())!= null) {
... //other code
object.customMethod(tagName, n.getNodeValue()); //occurs only once per iteration
Log.i("TAG", tagName + ": " + n.getNodeValue())
...//other code
}
The customMethod received a key and value pair and saves them as Strings using Android's SharedPreferences system. At the moment of being called, the method actually has the key=>value pair, but it appears the method is being called more than once during the same iteration loop. I came to know this after printing out the logcat sample showing the output after each call within customMethod due to having blanks/nulls saved in the preferences when I fetched them later. Why is this happening? A sample output is as shown:
TAG inserted: 500.00 //log call right after insertion within customMethod()
TAG vc:limit: 500.00 //log call after returning from customMethod()
TAG inserted:
TAG inserted:
TAG inserted: //other calls, which I want to know how and why they are occurring
All the above occurred during a single iteration of the while loop. Anyone know why this is happening? Something else, it seems the code right after the insertion only runs once, but only the code within the customMethod() gets called several times during the iteration. The custom method is as shown below:
public boolean customMethod(String key, String val) {
boolean inserted = prefs.edit().putString(key, val).commit(); //prefs is global
Log.i("TAG", (inserted == true ? "inserted: " + val : "not inserted"));
return inserted;
}
Edit: The full while loop as requested:
private void setSelectedID(int pos)
{
...
String id = IDs[pos];
...
NodeList descElements = MainActivity.root.getElementsByTagName(VCard.DIRECTORY); //DIRECTORY is a String constant
Element desc = (Element) descElements.item(0);
NodeIterator iterator = ((DocumentTraversal)MainActivity.doc).createNodeIterator(desc, NodeFilter.SHOW_ALL, null, true);
Node n;
VCard object = new VCard(this);
while((n = iterator.nextNode())!= null)
{
if(n.getNodeType() == Node.CDATA_SECTION_NODE || n.getNodeType() == Node.TEXT_NODE)
{
String tagName = n.getParentNode().getNodeName();
if(object.containsKey(tagName))
{
Element e = (Element) n.getParentNode();
if(e.hasAttribute("id") && e.getAttribute("id").equals(id))
{
object.customMethod(tagName, n.getNodeValue());
Log.i("TAG", tagName + ": " + n.getNodeValue())
}
}
}
}
}
I'm trying to put some Strings to a HashMap, but they wont add.
My code looks like this and I can't seem to understand why they won't add. Can someone help me and give me an explanation to what I'm doing wrong?
HashMap <String, String> akro = new HashMap <String, String>();
public void lesFil() {
try {
BufferedReader br = new BufferedReader(new FileReader("akronymer.txt"));
String line;
while((line = br.readLine()) != null) {
if(!line.contains(" ")) {
continue;
}
String[] linje = line.split("\\s+", 2);
String akronym = linje[0];
String betydning = linje[1];
// System.out.println(a + " || " + b);
akro.put(akronym, betydning);
}
} catch(Exception e) {
System.out.println("Feilen som ble fanget opp: " + e);
}
}
When I'm removing "//", both akronym and betydning prints out fine.
I tried to add this method to test the HashMap but nothing prints out and the size = 0
public void skrivUt() {
for(Map.Entry <String, String> entry : akro.entrySet()) {
System.out.print("Key: " + entry.getKey());
System.out.println(", Value: " + entry.getValue());
}
System.out.println("Antall akronymer: " + akro.size());
}
Part of the file I'm reading from(txt file):
...
CS Chip Select
CS Clear to Send
CS Code Segment
C/S Client/Server
...
Remember that a Map in Java maps one key to one value. In the sample data you provide, it seems that you have multiple values ("Chip Select", "Clear to Send", "Code Segment") for one key ("CS").
You can solve this by either picking a structure other than a Map, changing what you want to store, or changing the value of the Map to a List<String>.
For example:
List<String> values = akro.get(akronym);
if(values == null) {
values = new LinkedList<String>();
akro.put(akronym, values);
}
values.add(betydning);