I am reading a HashMap and creating a CSV file.
The below code accepts a HashMap and produce a CSV file. However the formatting is a problem. For a HashMap,
HashMap<String, Integer> hmap = new HashMap<String, Integer>();
hmap.put("Feature1", 1);
hmap.put("Feature2", 2);
It produces
Feature2,Feature2,
2,1,Feature1,Feature1,
2,1,
Expected Output (without comma at the end of each line):
Feature2,Feature1
2,1
Which is a wrong formatting
This is the code I use. How to fix it ?
public String appendCSV(Map featureset) throws IOException{
StringBuilder csvReport = new StringBuilder();
Map<String, Integer> map =featureset;
Set<String> keys = map.keySet();
String[] lsitofkeys = {};
for(String elements:keys){
for(int i =0 ; i< keys.size(); i++){
csvReport.append(elements+",");
}
csvReport.append("\n");
for(String key: keys){
csvReport.append(map.get(key).toString()+",");
}
}
return csvReport.toString();
}
Java 8 has String.join():
Having collected the keys and values into lists:
csvReport.append(String.join(",", keys));
csvReport.append(String.join(",", values));
The Streams API has Collectors.joining() which helps even more:
List<Entry> entries = new ArrayList<>(map.entrySet());
csvReport.append(entries.stream()
.map(e -> e.getKey())
.collect(Collectors.joining(","));
csvReport.append("\n");
csvReport.append(entries.stream()
.map(e -> e.getValue())
.collect(Collectors.joining(","));
csvReport.append("\n");
Both of these ultimately use StringJoiner. If you have an academic interest in how to build a joined string without a delimiter at the end, it's worth looking at the code for StringJoiner for an elegant example.
However - There are subtleties to writing CSV and it's a good idea to use a library unless there are reasons (legal, academic) not to. Apache Commons CSV is one.
seems you have issues with your loop
you need two separate loops (no inner loops);
Also to get rid of that comma at the end, you can use a simple check using a isFirst variable like below :)
public String appendCSV(Map featureset) throws IOException{
StringBuilder csvReport = new StringBuilder();
Map<String, Integer> map =featureset;
Set<String> keys = map.keySet();
String[] lsitofkeys = {};
boolean isFirst=true;
for(String elements : keys){
if(!isFirst){
csvReport.append(",");
}
csvReport.append(elements);
isFirst=false;
}
csvReport.append("\n");
isFirst=true;
for(String elements : keys){
if(!isFirst){
csvReport.append(",");
}
csvReport.append(map.get(elements));
isFirst=false;
}
return csvReport.toString();
}
Just remote the last character of your string if it is longer than 1 character. Here is how to do it: str.substring(0, str.length() - 1);
You should have a separate StringBuilder for the keys and another one for the values. Then as you go through your keys you add them to your key StringBuilder and then take the map given and grab the value associated with that key and add it to your value StringBuilder.
Lastly you just keep track of how many keys you have seen so far. If the number of keys seen is not equal to the size of the map then you append a comma. But if you are on the last element according to the numOfKeys counter, then you append nothing to the end of the StringBuilders.
StringBuilder csvKeyReport = new StringBuilder();
StringBuilder csvValueReport = new StringBuilder();
Map<String, Integer> map = hmap;
Set<String> keys = map.keySet();
int numOfKeys = 0;
for(String key : keys)
{
numOfKeys++;
String comma = numOfKeys == map.size() ? "" : ",";
csvKeyReport.append(key + comma);
csvValueReport.append(map.get(key) + comma);
}
csvKeyReport.append("\n");
csvKeyReport.append(csvValueReport.toString() + "\n");
System.out.print(csvKeyReport.toString());
Output
Feature2,Feature1
2,1
One way to achieve that is doing something like this:
import java.io.IOException;
import java.util.HashMap;
public class HashMapToCSV {
public static void main(String[] args) {
HashMap<String, Integer> hmap = new HashMap<String, Integer>();
hmap.put("Feature1", 1);
hmap.put("Feature2", 2);
try {
System.out.println(appendCSV(hmap));
} catch (IOException e){
e.printStackTrace();
}
}
public static String appendCSV(HashMap<String,Integer> featureset) throws IOException{
StringBuilder csvReport = new StringBuilder();
// loop through the keySet and append the keys
for(String key: featureset.keySet()){
csvReport.append(key+",");
}
// to remove the comma at the end
csvReport.replace(csvReport.length()-1, csvReport.length(), "");
csvReport.append("\n"); // append new line
// then loop through the keySet and append the values
for(String key: featureset.keySet()){
csvReport.append(featureset.get(key)+",");
}
csvReport.replace(csvReport.length()-1, csvReport.length(), "");
return csvReport.toString();
}
}
Output
Feature2,Feature1
2,1
You should to create a new stringbuilder into the cycle:
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class NewClass {
public NewClass() throws IOException {
HashMap<String, Integer> hmap = new HashMap<String, Integer>();
hmap.put("Feature1", 1);
hmap.put("Feature2", 2);
System.out.print(appendCSV(hmap));
}
public String appendCSV(Map featureset) throws IOException {
StringBuilder csvReport = new StringBuilder();
StringBuilder csvReportVal = new StringBuilder();
Set<String> keys = featureset.keySet();
for (String elements : keys) {
csvReport.append(elements + ",");
csvReportVal.append(featureset.get(elements).toString() + ",");
}
// Excluding the latest ","
csvReport.setLength(csvReport.length() - 1);
csvReportVal.setLength(csvReportVal.length() - 1);
csvReport.append("\n" + csvReportVal.toString());
return csvReport.toString();
}
public static void main(String[] args) throws IOException {
new NewClass();
}
}
OUTPUT:
Feature2,Feature1
2,1
Related
I'm trying to extract a certain character from a buffer that isn't ASCII. I'm reading in a file that contains movie names that have some non ASCII character sprinkled in it like so.
1|Tóy Story (1995)
2|GoldenEye (1995)
3|Four Rooms (1995)
4|Gét Shorty (1995)
I was able to pick off the lines that contained the non ASCII characters, but I'm trying to figure out how to get that particular character from the lines that have said non ASCII character and replace it with an ACSII character from the map I've made.
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
HashMap<Character, Character>Char_Map = new HashMap<>();
Char_Map.put('o','ó');
Char_Map.put('e','é');
Char_Map.put('i','ï');
for(Map.Entry<Character,Character> entry: Char_Map.entrySet())
{
System.out.println(entry.getKey() + " -> "+ entry.getValue());
}
try
{
BufferedReader br = new BufferedReader(new FileReader("movie-names.txt"));
String contentLine= br.readLine();
while(contentLine != null)
{
String[] contents = contentLine.split("\\|");
boolean result = contents[1].matches("\\A\\p{ASCII}*\\z");
if(!result)
{
System.out.println(contentLine);
//System.out.println();
}
contentLine= br.readLine();
}
}
catch (IOException ioe)
{
System.out.println("Cannot open file as it doesn't exist");
}
}
}
I tried using something along the lines of:
if((contentLine.charAt(i) == something
But I'm not sure.
You can just use replaceAll. Put this in the while loop, so that it works on each line you read from the file. With this change, you won't need the split and if (... matches) anymore.
contentLine.replaceAll("ó", "o");
contentLine.replaceAll("é", "e");
contentLine.replaceAll("ï", "i");
If you want to keep a map, just iterate over its keys and replace with the values you want to map to:
Map<String, String> map = new HashMap<>();
map.put("ó", "o");
// ... and all the others
Later, in your loop reading the contents, you replace all the characters:
for (Map.Entry<String, String> entry : map.entrySet())
{
String oldChar = entry.getKey();
String newChar = entry.getValue();
contentLine = contentLine.replaceAll(oldChar, newChar);
}
Here is a complete example:
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) throws Exception {
HashMap<String, String> nonAsciiToAscii = new HashMap<>();
nonAsciiToAscii.put("ó", "o");
nonAsciiToAscii.put("é", "e");
nonAsciiToAscii.put("ï", "i");
BufferedReader br = new BufferedReader(new FileReader("movie-names.txt"));
String contentLine = br.readLine();
while (contentLine != null)
{
for (Map.Entry<String, String> entry : nonAsciiToAscii.entrySet())
{
String oldChar = entry.getKey();
String newChar = entry.getValue();
contentLine = contentLine.replaceAll(oldChar, newChar);
}
System.out.println(contentLine); // or whatever else you want to do with the cleaned lines
contentLine = br.readLine();
}
}
}
This prints:
robert:~$ javac Main.java && java Main
1|Toy Story (1995)
2|GoldenEye (1995)
3|Four Rooms (1995)
4|Get Shorty (1995)
robert:~$
You want to flip your keys and values:
Map<Character, Character> charMap = new HashMap<>();
charMap.put('ó','o');
charMap.put('é','e');
charMap.put('ï','i');
and then get the mapped character:
char mappedChar = charMap.getOrDefault(inputChar, inputChar);
To get the chars for a string, call String#toCharArray()
Issue adding a list from one hashmap's value to another's
Basically, I have 2 hashmaps (map1 and map2), both have the same keys(Integers from 0-500), but different values. What I'm wanting to do is use the value of map1, which is a String, as the key and the value of map2, which is a List, as the value. Adding map1 as the key is working, no problem, but when I try to add map2's value as map's value, it just returns as null.
This is for a homework project, where we are given 2 .csv files, one with labels and another with fake image file names, and have to be able to search by either image label or image file name.
Map<String, List<String>> map = new HashMap<String, List<String>>();
#SuppressWarnings({ "resource", "null", "unlikely-arg-type" })
public ImageLabelReader(String labelMappingFile, String imageMappingFile) throws IOException {
Map<Integer, String> map1 = new HashMap<Integer, String>();
Map<Integer, List<String>> map2 = new HashMap<Integer, List<String>>();
BufferedReader labelIn = new BufferedReader(new FileReader(labelMappingFile));
BufferedReader imageIn = new BufferedReader(new FileReader(imageMappingFile));
String row;
String[] rowArray;
while ((row = labelIn.readLine()) != null) {
rowArray = row.split(" ", 2);
map1.put(Integer.parseInt(rowArray[0]), rowArray[1]);
}
labelIn.close();
while ((row = imageIn.readLine()) != null) {
rowArray = row.split(" ", 2);
if(map2.containsKey(Integer.parseInt(rowArray[1]))) {
List<String> tempList = map2.get(Integer.parseInt(rowArray[1]));
tempList.add(rowArray[0]);
} else {
List<String> l = new ArrayList<String>();
l.add(rowArray[0]);
map2.put(Integer.parseInt(rowArray[1]), l);
}
}
imageIn.close();
List<String> t = new ArrayList<String>();
for(int i = 0; i < map1.size(); i++) {
t.clear();
for(String s : map2.get(i)) {
t.add(s);
System.out.println(t);
}
map.put(map1.get(i), map2.get(i));
}
System.out.println(map.containsKey("burrito"));
System.out.print(map2.get("burrito"));
}
Output is "True null" when the output should be "True [list containing strings]"
Try replacing -
map.put(map1.get(i), map2.get(i));
with
map.put(map1.get(i), t);
And also -
System.out.print(map2.get("burrito"));
with
System.out.print(map.get("burrito"));
Also, you're trying to get map's value using a String while you said the key is of int type, please check that.
I will be given two files which I need to read into my program. One file will be a list of real words, while the other will be a list of those same words out of order. I need to output the scrambled words in alphabetical order with the real words printed next to them, and I need to do this using a Hashmap. My issue is that I can print out the scrambled word and 1 real word next to it, but in some cases there may be more than one real word for each jumbled word.
for example, my program can do this:
cta cat
stpo post
but I need it to be able to do this:
cta cat
stpo post stop
What changes do I need to make to my code to be able to have more than one dictionary word for each scrambled word? Thank you for your help. My code is below:
import java.io.*;
import java.util.*;
public class Project5
{
public static void main (String[] args) throws Exception
{
BufferedReader dictionaryList = new BufferedReader( new FileReader( args[0] ) );
BufferedReader scrambleList = new BufferedReader( new FileReader( args[1] ) );
HashMap<String, String> dWordMap = new HashMap<String, String>();
while (dictionaryList.ready())
{
String word = dictionaryList.readLine();
dWordMap.put(createKey(word), word);
}
dictionaryList.close();
ArrayList<String> scrambledList = new ArrayList<String>();
while (scrambleList.ready())
{
String scrambledWord = scrambleList.readLine();
scrambledList.add(scrambledWord);
}
scrambleList.close();
Collections.sort(scrambledList);
for (String words : scrambledList)
{
String dictionaryWord = dWordMap.get(createKey(words));
System.out.println(words + " " + dictionaryWord);
}
}
private static String createKey(String word)
{
char[] characterWord = word.toCharArray();
Arrays.sort(characterWord);
return new String(characterWord);
}
}
You need to do several changes. The biggest one is that dWordMap can't hold just one String - it needs to hold the list of words that are found in the scrambled words file.
The next change is being able to manipulate that list. I've added a sample solution which is untested but should give you a good place to start from.
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.*;
public class Projects {
public static void main (String[] args) throws Exception
{
BufferedReader dictionaryList = new BufferedReader( new FileReader( args[0] ) );
BufferedReader scrambleList = new BufferedReader( new FileReader( args[1] ) );
Map<String, List<String>> dWordMap = new HashMap<>();
while (dictionaryList.ready()) {
String word = dictionaryList.readLine();
dWordMap.put(createKey(word), new ArrayList<>());
}
dictionaryList.close();
while (scrambleList.ready()) {
String scrambledWord = scrambleList.readLine();
String key = createKey(scrambledWord);
List<String> list = dWordMap.get(key);
list.add(scrambledWord);
}
scrambleList.close();
for (Map.Entry<String, List<String>> entry : dWordMap.entrySet()) {
String word = entry.getKey();
List<String> words = entry.getValue();
Collections.sort(words);
System.out.println(concatList(words, " ") + " " + word );
}
}
private static String createKey(String word) {
char[] characterWord = word.toCharArray();
Arrays.sort(characterWord);
return new String(characterWord);
}
private static String concatList(List<String> list, String delimiter) {
StringJoiner joiner = new StringJoiner(delimiter);
list.forEach(joiner::add);
return joiner.toString();
}
}
There a few other changes I would have made - the first is to put the calls to dictionaryList.close(); and scrambleList.close(); in a finally part of a try...catch clause to make sure that the resources are freed in the end no matter what happens. You can also consider using Java 8's Streams to make the code more up to date. I'll be happy to give some more tips if this doesn't fit your needs or you have any more questions. Good luck!
If you want to record the list of dictionary words that are anagrams of each scrambled word then you will need to have a map to a list:
Map<String, List<String>> anagrams = new HashMap<>();
Then, for each scrambled word, you add a list of dictionary words to the map:
anagrams.put(scrambled, allAnagrams(scrambled));
Where allAnagrams would look like:
private List<String> allAnagrams(String scrambled) {
List<String> anagrams = new ArrayList<>();
for (String word: dictionary) {
if (isAnagram(word, scrambled))
anagrams.add(word);
}
Collections.sort(anagrams);
return anagrams;
}
Not that if you have Java 8 and are familiar with streams then this could be:
private List<String> allAnagrams(String scrambled) {
return dictionary.stream()
.filter(word -> isAnagram(scrambled, word))
.sorted()
.collect(Collectors.toList());
}
To improve upon #sprinter's Map<String, List<String>> example:
private final Map<String, List<String>> lookup = new HashMap<>();
public List<String> getList(String word) {
//can also make #computeIfAbsent use an "initializer" for the key
return lookup.computeIfAbsent(word, k -> new ArrayList<>());
}
Then it's simple to interact with:
List<String> words = getList("tspo"); //spot, post, stop, etc...
You can do the unscrambling from there, and could go even further if you wanted to save space and find a way to index the key as a specific list of characters (so that sotp and tpos would do only one lookup).
I have a data-structure of Map<String, List<String>> that follows the following code:
for (int i = 0; i < al_dwpi_par.size(); i++) {
if (!hash_features_dwpi_dc.containsKey(al_dwpi_par.get(i).getGA())) {
List<String> list = new ArrayList<String>();
list.add(al_dwpi_par.get(i).getDC());
hash_features_dwpi_dc.put(al_dwpi_par.get(i).getGA(), list);
} else {
hash_features_dwpi_dc.get(al_dwpi_par.get(i).getGA()).add(al_dwpi_par.get(i).getDC());
}
}`
This creates a Hash <key>,<List> where my list stores in each position information related to that key. Apparently that hash has no errors.
I'm trying to create a file where each element in that list will be a line related to that Key. Imagine that one element of that Hash is:
<1997>,<ball, house, ball, monkey, light, banana>. My file should be in the end something like 1997.results.txt and each line:
ball
house
ball
monkey
light
banana
I have tried to iterate through my Hash and some other things but was not successful. Even tried to work with Guava (as suggest by some similar posts), not good too.
Any idea/example/suggestion is more than welcome.
It sounds like you're just looking for
map.forEach((name, lines) -> {
try {
Files.write(Paths.get(name + ".results.txt"), lines);
} catch (IOException e) {
// do whatever
}
});
...assuming Java 8 is available.
Nice answer using Java 8. Here I come with my own approach, a little bit longer, hope it helps you or could be useful as a reference if Java 8 is not available. Use of NIO it is also useful :).
public static void main(String[] args) throws IOException {
//Given this information
Map<String, List<String>> dataMap = new HashMap<String, List<String>>();
List<String> valuesForKey = new ArrayList<String>();
valuesForKey.add("ball");
valuesForKey.add("house");
valuesForKey.add("ball");
valuesForKey.add("monkey");
valuesForKey.add("light");
valuesForKey.add("banana");
dataMap.put("1997", valuesForKey);
//I'd like to create a file:
createTextFileFromMap(dataMap);
}
private static void createTextFileFromMap(Map<String, List<String>> dataMap) throws IOException {
//Iterate the map to generate the number of files according to the items in your map
for (Map.Entry<String, List<String>> entries : dataMap.entrySet()) {
String filePath = "data/" + entries.getKey() + ".results.txt";//Generate a file with name based on key
String formattedValues = getFormattedData(entries.getValue());//Format the list values to a line separated list
BufferedWriter bwriter = new BufferedWriter(new FileWriter(new File(filePath)));//Use a BufferedWriter
bwriter.write(formattedValues);//Write the content
bwriter.close();//Close the writer
}
}
//Just a method that will iterate over your list to put your strings of the list in a single String in which values will be separated by lines
private static String getFormattedData(List<String> valueList) {
StringBuilder sbuilder = new StringBuilder();
for (String word : valueList) {
sbuilder.append(word).append(System.getProperty("line.separator"));
}
return sbuilder.toString();
}
Happy coding :)
I have a text file containing domains like
ABC.COM
ABC.COM
DEF.COM
DEF.COM
XYZ.COM
i want to read the domains from the text file and check how many instances of domains are there.
Reading from a text file is easy but i am confused at how to check number of instances of domains.
Please help.
Split by space (String instances have method split), iterate through result array and use Map<String(domainName), Integer(count)> - when domain is in map, than increase count in map by 1, when not - put domain name in map and set 1 as a value.
Better solution is to use a Map to map the words Map with frequency.
Map<String,Integer> frequency = new LinkedHashMap<String,Integer>();
Read file
BufferedReader in = new BufferedReader(new FileReader("infilename"));
String str;
while ((str = in.readLine()) != null) {
buildMap(str);
}
in.close();
Build map method : You can split the urls in your file by reading them line by line and splitting with delimiter(in your case space).
String [] words = line.split(" ");
for (String word:words){
Integer f = frequency.get(word);
if(f==null) f=0;
frequency.put(word,f+1);
}
Find out for a particular domain with:
frequency.get(domainName)
Ref: Counting frequency of a string
List<String> domains=new ArrayList<String>(); // values from your file
domains.add("abc.com");
domains.add("abc.com");
domains.add("xyz.com");
//added for example
Map<String,Integer> domainCount=new HashMap<String, Integer>();
for(String domain:domains){
if(domainCount.containsKey(domain)){
domainCount.put(domain, domainCount.get(domain)+1);
}else
domainCount.put(domain, new Integer(1));
}
Set<Entry<String, Integer>> entrySet = domainCount.entrySet();
for (Entry<String, Integer> entry : entrySet) {
System.out.println(entry.getKey()+" : "+entry.getValue());
}
If the domains are unknown you can do something like:
// Field Declaration
private Map<String, Integer> mappedDomain = new LinkedHashMap<String, Integer>();
private static final List<String> domainList = new ArrayList<String>();
// Add all that you want to track
domainList.add("com");
domainList.add("net");
domainList.add("org");
...
// Inside the loop where you do a readLine
String[] words = line.split(" ");
for (String word : words) {
String[] wordSplit = word.split(".");
if (wordSplit.length == 2) {
for (String domainCheck : domainList) {
if (domainCheck.equals(wordSplit[1])) {
if (mappedDomain.containsKey(word)) {
mappedDomain.put(word, mappedDomain.get(word)+1);
} else {
mappedDomain.put(word, 1);
}
}
}
}
}
Note: This will work for something like xxx.xxx; if you need to take care of complex formats you need to modify the logic from wordSplit!