Using an answer I found here on SO I have found a way to write out my resultset to a csv file. However it currently just writes every element of the array to a new column. How would I alter the following code to change format to create new row, on every xth element like below?
int value = 2
Current format: a, b, c, d, e, f
Desired format: a, b,
c, d,
e, f
I know I can utilize the modulo of the int value, but am unsure how to write to a specific column or row.
private static final String DEFAULT_SEPARATOR = " ";
public static void writeLine(Writer w, List<String> values, String separators, String customQuote) throws IOException {
boolean first = true;
//default customQuote is empty
if (separators == " ") {
separators = DEFAULT_SEPARATOR;
}
StringBuilder sb = new StringBuilder();
for (String value : values) {
if (!first) {
sb.append(separators);
}
if (customQuote == " ") {
sb.append(followCVSformat(value));
} else {
sb.append(customQuote).append(followCVSformat(value)).append(customQuote);
}
first = false;
}
sb.append("\n");
w.append(sb.toString());
}
private static String followCVSformat(String value) {
String result = value;
if (result.contains("\"")) {
result = result.replace("\"", "\"\"");
}
return result;
}
public static void writeLine(
Writer w, List<String> values, String separators, String customQuote, int elementsPerRow)
throws IOException {
...
int counter = 0;
for (String value : values) {
if (!first) {
sb.append(separators);
}
if (counter != 0 && counter % elementsPerRow == 0)
sb.append("\n");
if (customQuote == " ") {
sb.append(followCVSformat(value));
} else {
sb.append(customQuote).append(followCVSformat(value)).append(customQuote);
}
first = false;
counter++;
}
...
Related
I want to write codes using a static recursive method in Java, cleanString(String s) that accepts a string of letters s and returns a string where adjacent letters that are the same are replaced by a single occurrence of that letter. The method is case-sensitive.
For example:
cleanString("sensssaatiionnaallll!") -> "sensational!"
cleanString("PPProoggggraamm") -> "Program"
cleanString("Lletterriiing") -> "Lletering"
Try this:
public class Main {
public static void main(String[] args) {
System.out.println(cleanString("sensssaatiionnaallll!"));
}
static String cleanString(String input)
{
if(input.length()<1) //To stop infinite recursion
return input;
var first = input.charAt(0);
var count = input.chars().takeWhile(x -> x == first).count();
return first + cleanString(input.substring((int)count));
}
}
First, it checks if the length of the string is less than 1. If it is, return the string itself (which is empty) and stop the recursion.
Next get the first character of the string. (e.g PPProoggggraamm -> P)
Get the number of characters in the start that equal the first character (3 in the case of PPProoggggraamm)
Call the function again, but this time lopping off the first n characters from the above step, and prepending the first character. ('P' + cleanString("rooggggraamm"))
Shortest recursive code to remove adjacent characters from the input string.
public class StackOverflow {
static String cleanString(String input) {
return input==null || input.length()<=1?input:cleanStringWrapper(input.substring(1),input.substring(0,1));
}
static String cleanStringWrapper(String input, String result) {
if (input.length() - 1 <= 0) {
return result+(result.charAt(result.length() - 1)!=input.charAt(0)?input:"");
} else {
return cleanStringWrapper(input.substring(1), result+(result.charAt(result.length() - 1) != input.charAt(0)?input.charAt(0):""));
}
}
public static void main(String[] args)
{
System.out.println(cleanString("OOPS"));
}
}
Output:
cleanString("sensssaatiionnaallll!") -> "sensational!"
cleanString("PPProoggggraamm") -> "Program"
cleanString("Lletterriiing") -> "Lletering"
cleanString("Gooooogle") -> "Gogle"
cleanString("ABC") -> "ABC"
cleanString("A") -> "A"
cleanString("") -> ""
cleanString(null) -> null
It just generate a new String and exclude the repeat characters.
static String cleanString(String input) {
if(input == null) return null;
char lastChar = 0;
StringBuilder output = new StringBuilder(input.length());
for (int i=0,n=input.length(); i<n; i++) {
char c = input.charAt(i);
if(c != lastChar) {
lastChar = c;
output.append(c);
}
}
return output.toString();
}
Recursive method:
public class Example {
public static int main(String[] args) {
String input = "sensssaatiionnaallll";
String output = cleanString(input, 0);
System.out.println(output); // print: sensational
return 0;
}
private static String cleanString(String input, int index) {
if(input == null) return "";
if(index >= input.length()) return "";
StringBuilder output = new StringBuilder();
char current = input.charAt(index);
int nextIndex = index + 1;
if(nextIndex >= input.length()) {
return output.append(current).toString();
}
char next = input.charAt(nextIndex);
if (current != next) {
output.append(current);
}
output.append(cleanString(input, nextIndex));
return output.toString();
}
}
Why you want to make static method for that?
Whay i understood is that you want to remove repeated characters from your input string.
You can do it below code as well.
StringBuilder sb = new StringBuilder();
str.chars().distinct().forEach(c -> sb.append((char) c));
If you want you can make a method of this 2 lines as a feature in your code.
Hope this helps!
I am trying to compare lines from a text file in Java.
For example, there is a text file with these lines:
temp1 am 32.5 pm 33.5 temp2 am 33.5 pm 33.5 temp3 am 32.5 pm
33.5 temp4 am 31.5 pm 35
a b c d e
a is the name of the line, b is constant(am), c is a variable, d is constant(pm), e is another variable.
It will only compare the variables -> temp1(c) to temp2(c), temp1(e) to temp2(e) etc.
When there are two or more lines with the same c(s) and e(s), it will throw FormatException.
From the example text file above, because temp1's c is the same as temp3's c and temps1's e is the same as temp3's e, it will throw FormatException.
This is what I have so far:
public static Temp read(String file) throws FormatException {
String line = "";
FileReader fr = new FileReader(fileName);
Scanner scanner = new Scanner(fr);
while(scanner.hasNextLine()) {
String line = scanner.nextLine();
System.out.println(line);
}
scanner.close();
if () {
throw new FormatException("Error.");
How can I make this?
You will need to split your lines to extract your variables and a Set to check for duplicates as next:
Set<String> ceValues = new HashSet<>();
while(scanner.hasNextLine()) {
String line = scanner.nextLine();
String[] values = line.split(" ");
if (!ceValues.add(String.format("%s %s", values[2], values[4]))) {
// The value has already been added so we throw an exception
throw new FormatException("Error.");
}
}
As I don't want to do your homework for you, let me get you started:
while(scanner.hasNextLine()) {
String line = scanner.nextLine();
String[] partials = line.split(" ");
String a = partials[0];
//...
String e = partials[4];
}
I'm splitting the line over a space as this is the only thing to split over in your case. This gives us 5 seperate strings (a through e). You will need to save them in a String[][] for later analysis but you should be able to figure out for yourself how to do this.
Try playing around with this and update your question if you're still stuck.
Here you got an example that basically includes:
a collection in which store your lines
simple pattern matching logic (see Java Regex Tutorial for more)
a try-with-resource statement
a recursive check method
First of all I would make a simple POJO representing a line info:
public class LineInfo {
private String lineName;
private String am;
private String pm;
public LineInfo(String lineName, String am, String pm) {
this.lineName = lineName;
this.am = am;
this.pm = pm;
}
// getters and setters
}
Second I would need a pattern to validate each line and extract data from them:
// group 1 group 2 group3 group 4 group 5
// v v v v v
private static final String LINE_REGEX = "(\\w+)\\s+am\\s+(\\d+(\\.\\d+)?)\\s+pm\\s+(\\d+(\\.\\d+)?)";
private static final Pattern LINE_PATTERN = Pattern.compile(LINE_REGEX);
Third I would rework the read method like this (I return void for simplicity):
public static void read(String fileName) throws FormatException {
// collect your lines (or better the information your lines provide) in some data structure, like a List
final List<LineInfo> lines = new ArrayList<>();
// with this syntax your FileReader and Scanner will be closed automatically
try (FileReader fr = new FileReader(fileName); Scanner scanner = new Scanner(fr)) {
while (scanner.hasNextLine()) {
final String line = scanner.nextLine();
final Matcher matcher = LINE_PATTERN.matcher(line);
if (matcher.find()) {
lines.add(new LineInfo(matcher.group(1), matcher.group(2), matcher.group(4)));
} else {
throw new FormatException("Line \"" + line + "\" is not valid.");
}
}
// recursive method
compareLines(lines, 0);
} catch (final IOException e) {
e.printStackTrace();
// or handle it in some way
}
}
private static void compareLines(List<LineInfo> lines, int index) throws FormatException {
// if there are no more lines return
if (index == lines.size()) {
return;
}
final LineInfo line = lines.get(index);
for (int i = index + 1; i < lines.size(); i++) {
final LineInfo other = lines.get(i);
// do the check
if (line.getAm().equals(other.getAm()) && line.getPm().equals(other.getPm())) {
throw new FormatException(String.format("Lines #%d (%s) and #%d (%s) does not meet the requirements.",
index, line.getLineName(), i, other.getLineName()));
}
}
// do the same thing with the next line
compareLines(lines, index + 1);
}
If I got your question right then you need to check line by line in order to find duplicates using c and e as criteria
this means, line n must be compared against all the other lines, if repeated then exception...
The suggestion will be:
Define a class that represent the element c and e of every line...
class LinePojo {
private String c;
private String e;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((c == null) ? 0 : c.hashCode());
result = prime * result + ((e == null) ? 0 : e.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
LinePojo other = (LinePojo) obj;
if (c == null) {
if (other.c != null)
return false;
} else if (!c.equals(other.c))
return false;
if (e == null) {
if (other.e != null)
return false;
} else if (!e.equals(other.e))
return false;
return true;
}
#Override
public String toString() {
return "(c=" + c + ", e=" + e + ")";
}
public LinePojo(String c, String e) {
this.c = c;
this.e = e;
}
}
then a list of that class where every line will be inserted and /or check if an element is there or not..
List<LinePojo> myList = new ArrayList<LinePojo>();
then iterate line by line
while(scanner.hasNextLine()) {
String line = scanner.nextLine();
String[] lineInfo = line.split(" ");
LinePojo lp = new LinePojo(lineInfo[2], lineInfo[4]);
if (myList.contains(lp)) {
throw new IllegalArgumentException("there is a duplicate element");
} else {
myList.add(lp);
}
}
So I have run into a problem where I have an ArrayList where the List is comprised of one letter strings. In this case (A,B,C,D,F,J,N) where the size of the list is 7.
Now I am trying to write code making all combinations of lettering that can be made where the order does not matter i.e. (I know it will be involving "n choose k") up to 5 letters long.
So for 7 choose 1 will be A,B,C,D,F,J,N
... 7 choose 2 ... etc.
... 7 choose 3 ... etc.
... etc.
I am then looking to store these string combinations into another list/hashmap (haven't decided on yet).
But my main focus is on the code that would generate such strings. If anyone can help that would be greatly appreciated. I also want to make it modular just in case i want to eventually form other combinations of 6,7 length. (Which is why I am not just doing it with 5 loops and incrementing for different indices).
What I have so far...
public class ReadFile {
public static void main(String[] args) throws IOException {
String file_name = "C:/Users/Shane/Documents/College/Classes/PurchaseTable.txt";
extract(file_name, 50);
}
private String path;
public ReadFile(String file_path) {
path= file_path;
}
public String[] OpenFile() throws IOException {
FileReader fr = new FileReader(path);
BufferedReader textReader = new BufferedReader(fr);
int numberOfLines = readLines();
String[] textData = new String[numberOfLines];
int i;
for(i=0; i < numberOfLines; i++) {
textData[i] = textReader.readLine();
}
textReader.close();
return textData;
}
int readLines() throws IOException {
FileReader file_to_read = new FileReader(path);
BufferedReader bf = new BufferedReader(file_to_read);
String aLine;
int numberOfLines = 0;
while(( aLine = bf.readLine()) != null) {
numberOfLines++;
}
bf.close();
return numberOfLines;
}
public static void extract(String filename, int threshold) {
String file_name = filename;
ArrayList<String> temp = new ArrayList<String>();
ArrayList<String> products = new ArrayList<String>();
HashMap<Integer, String> productsPerDate = new HashMap<Integer, String>();
//HashMap<Integer, String> allCombinations = new HashMap<Integer, String>();
try {
ReadFile file = new ReadFile(file_name);
String[] aryLines = file.OpenFile();
int i;
for (i=1; i < aryLines.length; i++) { //excludes header section of any table as shown in assignment
temp.add(aryLines[i]);
}
}
catch (IOException e) {
System.out.println( e.getMessage() );
}
System.out.println(temp);
System.out.println(temp.get(0));
System.out.println(temp.size());
int i; int j; int l;
for (i=0; i<temp.size(); i++) {
String str = temp.get(i);
StringBuilder sb = new StringBuilder(str);
int k =0;
for (j=0; j<=sb.length(); j++) {
if(sb.charAt(j) == '\"' && k==0) {
sb.delete(0, j+1);
k++;
}
if(sb.charAt(j) == '\"' && k!=0) {
sb.delete(j, sb.length());
String line = null;
System.out.println(sb);
for( l=0; l<sb.length(); l++) {
String string = Character.toString(sb.charAt(l));
if(string.equals(",")) {
}
else if (l ==0) {
products.add(string);
line = string;
}
else {
products.add(string);
line = line + string;
}
}
productsPerDate.put(i, line);
//System.out.println(products);
break;
}
}
}
System.out.println(products);
System.out.println(productsPerDate.entrySet()); //Hashmap set to string of 1 letter characters for products per date
Set<String> removeDup = new HashSet<>();
removeDup.addAll(products);
products.clear();
products.addAll(removeDup);
System.out.println(products);
int maxLength = productsPerDate.get(0).length();
for(int m = 0; m < productsPerDate.size(); m++) { //determine max length of string in hashmap
if(maxLength < productsPerDate.get(m).length()) {
maxLength = productsPerDate.get(m).length();
}
}
This probably isn't the most efficient way to do this but please bear with me and help in any way you can.
The output is shown below of what has been created in the above code:
1,"A,B,C,N",1/3/2013
4
A,B,C,N
B,C,D,A,F
A,C,V,N,J
A,C,J,D
[A, B, C, N, B, C, D, A, F, A, C, V, N, J, A, C, J, D]
[0=ABCN, 1=BCDAF, 2=ACVNJ, 3=ACJD]
[A, B, C, D, F, V, J, N]
So essentially I am trying to write the code to make all the possible combinations of length 5 string using the letter strings contained in the array list shown in last output.
Here is a little method that returns a list of all letter combinations of length k (order doesn't matter), given an input String of length n:
public static ArrayList<String> combinations(String nChars, int k) {
int n = nChars.length();
ArrayList<String> combos = new ArrayList<String>();
if (k == 0) {
combos.add("");
return combos;
}
if (n < k || n == 0)
return combos;
String last = nChars.substring(n-1);
combos.addAll(combinations(nChars.substring(0, n-1), k));
for (String subCombo : combinations(nChars.substring(0, n-1), k-1))
combos.add(subCombo + last);
return combos;
}
public static void main(String[] args) {
String nChars = "ABCDE";
System.out.println(combinations(nChars, 2));
}
output: [AB, AC, BC, AD, BD, CD, AE, BE, CE, DE]
I used Strings as input and output, since they are immutable and more well-behaved with regard to slicing than Lists. But if your List contains only 1-letter Strings, it should be easy to convert.
I don't know if this recursive implementation is performant, but it reflects nicely the mathematical property of the Pascal triangle: (n choose k) = (n-1 choose k-1) + (n-1 choose k)
Brute force, without recursion, with generics, not optimized, didactic.
If you want arrangements rather than combinaisons, just comment one line.
// COMBINAISONS
/**
* Return combinaisons of input
* #param _input
* #param _n how many to pick
* #return
*/
public static <T> Vector<Vector<T>> combinaisons (Vector<T> _input, int _n)
{
Vector<Vector<T>> output=new Vector<Vector<T>> ();
int size=_input.size();
// Current result
Object current[]=new Object[_n];
Arrays.fill(current,"");
// which element we take at each box (between 0 and size-1)
int current_indices[]=new int[_n];
Arrays.fill(current_indices,-1);
// inputs used
boolean used[]=new boolean [size];
Arrays.fill(used, false);
// Which box are we processing
int current_box=0;
// Next value for next position
int next_pos_value=0;
// ALGORITHM
while (true)
{
// Finished ?
if (current_box<0)
break;
// Last element ?
if (current_box>=_n)
{
// => save group
output.add(new Vector<T>((List<T>) Arrays.asList(current)));
current_box--;
continue;
}
// filling Current box > 0 && < _n
// next value available
int last_value=current_indices[current_box];
int next_value=-1;
// Where do we begin
int begin_test=0;
if (last_value>=0)
begin_test=last_value+1;
// bigger
// comment this for arrangement rather than combinaisons
if (begin_test<next_pos_value) begin_test=next_pos_value;
for (int test_value=begin_test; test_value < size; test_value++)
if (!used[test_value])
{
next_value=test_value;
break;
}
// VALUE AVAILABLE
if (next_value!=-1)
// valid value ?
{
// release
if (last_value!=-1)
used[last_value]=false;
used[next_value]=true;
current_indices[current_box]=next_value;
current[current_box]=_input.get(next_value);
// next position
current_box++;
// like arrangements, but next value always more
next_pos_value=next_value+1;
continue;
}
else
// invalid value (too big) ?
{
// release
if (last_value!=-1)
used[last_value]=false;
current_indices[current_box]=-1;
// back position
current_box--;
// like arrangements, but reset this
next_pos_value=-1;
continue;
}
}
return output;
}
// public static Vector<Vector<T>> combinaisons (Vector<T> _input)
I have string H2SO4 for example, how can i parse to int 4 after O? I can't use substring(4), because user can type for example NH3PO4 and there 4 is substring(5), so how can I parse any character that is exactly after O?
Thanks for help.
Your question is not clear, but this may work for your case.
String str="NH3PO4";
int lastChar=str.lastIndexOf("O");//replace "O" into a param if needed
String toParse=str.substring(lastChar+1);
System.out.println("toParse="+toParse);
try{
System.out.println("after parse, " +Integer.parseInt(toParse));
}
catch (NumberFormatException ex){
System.out.println(toParse +" can not be parsed to int");
}
}
I think you need to split your String to char array' and then search the 'o' in that array:
String str = "H2SO4";
char[] charArray = str.toCharArray();
Then you got : [H, 2, S, O, 4], and you can search the "O" in this array.
Hope it helped!
There are multiple ways, all of them very simple and taken from Official documentation on String.
//Find character index of O, and parse next character as int:
int index = str.indexOf("O");
Integer.parseInt(str.subString(index, index+1));
//loop trough char array and check each char
char[] arr = str.toCharArray();
for(char ch : arr){
if(isNumber(ch){..}
}
boolean isNumber(char ch){
//read below
}
refer to ascii table and here
you can use regular expression.
.*O([0-9]+).*
And use group to extract the number proceeding character O.
Find out more here:
http://docs.oracle.com/javase/tutorial/essential/regex/groups.html
final int numAfterO;
final String strNum;
final int oIndex = chemicalName.lastIndexOf("O");
if (oIndex >= 0 && chemicalName.length() >= oIndex + 2) {
strNum = chemicalName.subString(oIndex, oIndex + 1);
} else {
strNum = null;
}
if (strNum != null) {
try {
numAfterO = Integer.parseInt(strNum);
} catch (NumberFormatException e) {
numAfter0 = -1;
}
}
android.util.Log.d("MYAPP", "The number after the last O is " + numberAfterO);
I assume this is what you want.
In order to parse every character after exactly O you can use the follow code:
char [] lettersArray = source.toCharArray();
for(int i =0 ;i<lettersArray.length;i++){
if(Character.isLetter(lettersArray[i])){
if(lettersArray[i]=='O'){
try{
int a = Interger.parseInteger(lettersArray[i].toString());
}catch(Exception e){
e.printStackTrace();
}
}
}
}
Convert the String to a char array:
String molecule = "H2SO4 ";
char[] moleculeArray = str.toCharArray();
for(int i = 0; i < moleculeArray.length; i++){
if(Character.isLetter(moleculeArray[i])){
//Huston we have a character!
if(i+1 < moleculeArray.length && Character.isDigit(moleculeArray[i+1]) {
int digit = Character.getNumericValue(Character.isDigit(moleculeArray[i+1]);
//It has a digit do something extra!
}
}
}
then iterate over the array and use Character.isDigit(c) and Character.isLetter(c)
Here's something that parses an entire molecule structure. This one parses integers > 9 as well.
public static class Molecule {
private List<MoleculePart> parts = new ArrayList<MoleculePart>();
public Molecule(String s) {
String name = "";
String amount = "";
for (char c : s.toCharArray()) {
if (inBetween(c, 'A', 'Z')) {
if (!name.isEmpty()) // first iteration, the name is still empty. gotta omit.
save(name, amount);
name = "";
amount = "";
name += c; //add it to the temporary name
}
else if (inBetween(c, 'a', 'z'))
name += c; //if it's a lowercase letter, add it to the temporary name
else if (inBetween(c, '0', '9'))
amount += c;
}
save(name, amount);
}
public String toString() {
String s = "";
for (MoleculePart part : parts)
s += part.toString();
return s;
}
//add part to molecule structure after some parsing
private void save(String tmpMoleculename, String amount) {
MoleculePart part = new MoleculePart();
part.amount = amount.isEmpty() ? 1 : Integer.parseInt(amount);
part.element = Element.valueOf(tmpMoleculename);
parts.add(part);
}
private static boolean inBetween(char c, char start, char end) {
return (c >= start && c <= end);
}
}
public static class MoleculePart {
public Element element;
public int amount;
public String toString() {
return element.name() + (amount > 1 ? amount : "");
}
}
public static enum Element {
O, S, H, C, Se, Ni //add as many as you like
}
public static void main(String[] args) {
System.out.println(new Molecule("Ni84OH43Se"));
}
I am trying to count frequency of words in a text file. But I have to use a different approach. For example, if the file contains BRAIN-ISCHEMIA and ISCHEMIA-BRAIN, I need to count BRAIN-ISCHEMIA twice (and leaving ISCHEMIA-BRAIN) or vice versa. Here is my piece of code-
// Mapping of String->Integer (word -> frequency)
HashMap<String, Integer> frequencyMap = new HashMap<String, Integer>();
// Iterate through each line of the file
String[] temp;
String currentLine;
String currentLine2;
while ((currentLine = in.readLine()) != null) {
// Remove this line if you want words to be case sensitive
currentLine = currentLine.toLowerCase();
temp=currentLine.split("-");
currentLine2=temp[1]+"-"+temp[0];
// Iterate through each word of the current line
// Delimit words based on whitespace, punctuation, and quotes
StringTokenizer parser = new StringTokenizer(currentLine);
while (parser.hasMoreTokens()) {
String currentWord = parser.nextToken();
Integer frequency = frequencyMap.get(currentWord);
// Add the word if it doesn't already exist, otherwise increment the
// frequency counter.
if (frequency == null) {
frequency = 0;
}
frequencyMap.put(currentWord, frequency + 1);
}
StringTokenizer parser2 = new StringTokenizer(currentLine2);
while (parser2.hasMoreTokens()) {
String currentWord2 = parser2.nextToken();
Integer frequency = frequencyMap.get(currentWord2);
// Add the word if it doesn't already exist, otherwise increment the
// frequency counter.
if (frequency == null) {
frequency = 0;
}
frequencyMap.put(currentWord2, frequency + 1);
}
}
// Display our nice little Map
System.out.println(frequencyMap);
But for the following file-
ISCHEMIA-GLUTAMATE
ISCHEMIA-BRAIN
GLUTAMATE-BRAIN
BRAIN-TOLERATE
BRAIN-TOLERATE
TOLERATE-BRAIN
GLUTAMATE-ISCHEMIA
ISCHEMIA-GLUTAMATE
I am getting the following output-
{glutamate-brain=1, ischemia-glutamate=3, ischemia-brain=1, glutamate-ischemia=3, brain-tolerate=3, brain-ischemia=1, tolerate-brain=3, brain-glutamate=1}
The problem is in second while block I think. Any light on this problem will be highly appreciated.
From an algorithm perspective, you may want to consider the following approach:
For each string, split, then sort, then re-combine (i.e. take DEF-ABC and convert to ABC-DEF. ABC-DEF would convert to ABC-DEF). Then use that as the key for your frequency count.
If you need to hold onto the exact original item, just include that in your key - so the key would have: ordinal (the re-combined string) and original.
Disclaimer: I stole the sweet trick suggested by Kevin Day for my implementation.
I still want to post just to let you know that using the right data structure (Multiset/Bad) and the right libraries (google-guava) will not only simplify the code but also makes it efficient.
Code
public class BasicFrequencyCalculator
{
public static void main(final String[] args) throws IOException
{
#SuppressWarnings("unchecked")
Multiset<Word> frequency = Files.readLines(new File("c:/2.txt"), Charsets.ISO_8859_1, new LineProcessor() {
private final Multiset<Word> result = HashMultiset.create();
#Override
public Object getResult()
{
return result;
}
#Override
public boolean processLine(final String line) throws IOException
{
result.add(new Word(line));
return true;
}
});
for (Word w : frequency.elementSet())
{
System.out.println(w.getOriginal() + " = " + frequency.count(w));
}
}
}
public class Word
{
private final String key;
private final String original;
public Word(final String orig)
{
this.original = orig.trim();
String[] temp = original.toLowerCase().split("-");
Arrays.sort(temp);
key = temp[0] + "-"+temp[1];
}
#Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((getKey() == null) ? 0 : getKey().hashCode());
return result;
}
#Override
public boolean equals(final Object obj)
{
if (this == obj)
{
return true;
}
if (obj == null)
{
return false;
}
if (!(obj instanceof Word))
{
return false;
}
Word other = (Word) obj;
if (getKey() == null)
{
if (other.getKey() != null)
{
return false;
}
}
else if (!getKey().equals(other.getKey()))
{
return false;
}
return true;
}
#Override
public String toString()
{
return getOriginal();
}
public String getKey()
{
return key;
}
public String getOriginal()
{
return original;
}
}
Output
BRAIN-TOLERATE = 3
ISCHEMIA-GLUTAMATE = 3
GLUTAMATE-BRAIN = 1
ISCHEMIA-BRAIN = 1
Thanks everyone for your help. Here is how I solved it-
// Mapping of String->Integer (word -> frequency)
TreeMap<String, Integer> frequencyMap = new TreeMap<String, Integer>();
// Iterate through each line of the file
String[] temp;
String currentLine;
String currentLine2;
while ((currentLine = in.readLine()) != null) {
temp=currentLine.split("-");
currentLine2=temp[1]+"-"+temp[0];
// Iterate through each word of the current line
StringTokenizer parser = new StringTokenizer(currentLine);
while (parser.hasMoreTokens()) {
String currentWord = parser.nextToken();
Integer frequency = frequencyMap.get(currentWord);
Integer frequency2 = frequencyMap.get(currentLine2);
// Add the word if it doesn't already exist, otherwise increment the
// frequency counter.
if (frequency == null) {
if (frequency2 == null)
frequency = 0;
else {
frequencyMap.put(currentLine2, frequency2 + 1);
break;
}//else
} //if (frequency == null)
frequencyMap.put(currentWord, frequency + 1);
}//while (parser.hasMoreTokens())
}//while ((currentLine = in.readLine()) != null)
// Display our nice little Map
System.out.println(frequencyMap);