Trying to sort the doubles in descending order from my .txt file and print out the results, but why am I getting 4 lines of []?
My text file looks like this:
Mary Me,100.0
Hugh More,50.8
Jay Zee,85.0
Adam Cop,94.5
with my code that looks like this:
public static void sortGrade() throws IOException
{
Scanner input = new Scanner(new File("Grades.txt"));
while(input.hasNextLine())
{
String line = input.nextLine();
ArrayList<Double> grades = new ArrayList<Double>();
Scanner scan = new Scanner(line);
scan.useDelimiter(",");
while(scan.hasNextDouble())
{
grades.add(scan.nextDouble());
}
scan.close();
Collections.sort (grades,Collections.reverseOrder());
System.out.println(grades);
}
input.close();
}
I'd like for the output to look like this:
Hugh More,50.8
Jay Zee,85.0
Adam Cop,94.5
Mary Me,100.0
A push in the right direction would be great, thanks.
The problem is you're not reading in your values correctly!
You're reading in your line here:
String line = input.nextLine();
And then trying to parse it with a second one but this:
scan.hasNextDouble()
Will always return false as the first token in each string is the name! And it's not a double. You need to change the way you're parsing your input.
Furthermore if you want to sort both the name and the score at the same time you have to create an object that would encapsulate both name and grade and implement Comparable or write a custom Comparator for that type. Otherwise you'd have to make a Map mapping grade to each name, sort the grades and then print it in order while getting names for each grade (there can be multiple names for the same grade). This is not recommended because it does look clumsy.
Writing a comparable class really isn't that hard you just need to implement one method :-)
#Edit: you don't need a second scanner, if your format is set and that easy just use a split on that line like this:
String[] gradeName = line.split(",");
grades.add(Double.parseDouble(gradeName[1]));
If you can have more than 1 grade per person than instead of just getting gradeName[1] iterate over gradeName starting from the element at index 1 (since 0 is the name).
#Edit2:
You are creating a new grades list in the loop every time, so it will read one entry, add it to the list, sort it and print it. You should pull out everything except for those lines outside the while loop:
String line = input.nextLine();
String[] gradeName = line.split(",");
grades.add(Double.parseDouble(gradeName[1]));
#Edit3:
If you want an ascending order don't use Collections.reverseOrder(), just the default one:
Collections.sort (grades);
Related
I am creating a simple program to data read from a text file. The file stores information about a person, with the name, age and a number on each line:
Eg: File format per line
Francis Bacon 50 2
I can read in a file no problem if it is just text, but I am confused on how to differentiate between text and numbers. Here is a look at my code:
import java.io.*;
public class Test{
private People people[] = new People[5];
public Test(){
BufferedReader input;
input = new BufferedReader(new FileReader("People.txt"));// file to be readfrom
String fileLine;
int i = 0;
while (test != null){
fileLine = input.readLine();
// Confused as to how to parse this line into seperate parts and store in object:
// eg:
people[i].addName(fileLine - part 1);
people[i].addBookNo(fileLine - part 2);
people[i].addRating(fileLine - part 3)
i++
}
}
}
I strongly suggest you use the Scanner class instead. That class provides you with methods such as nextInt and so on.
You could use it to read from the file directly like this:
Scanner s = new Scanner(new File("People.txt"));
while (s.hasNext()) {
people[i].addName(s.next());
people[i].addBookNo(s.nextInt());
people[i].addRating(s.nextInt());
}
(Just realized that you may have spaces in the name. That complicates things slightly, but I would still consider using a scanner.)
An alternative solution would be to use a regular expression and groups to parse the parts. Something like this should do:
(.*?)\s+(\d+)\s+(\d+)
The following regex works on these 3 cases, breaking them into 3 matched groups.
Regex
(.*)\s+(\d+)\s+(\d+)
Cases
Francis Bacon 50 2
Jill St. John 20 20
St. Francis Xavier III 3 3
If you want to do in this way, you can try doing like this :
Fixing the way data will be present in the file, say
firstName.lastName.age.number;
Then you can write code to read data upto . and store it in a variable (you will be knowing what it is meant for) and after ";" there will be second entry.
I'm trying to understand file I/O for class and I understand the basics but I'm having trouble understanding how to manage whats in the input file, the input file is formatted like this:
BusinessContact:firstName=Nikolaos;lastName=Tsantalis
SocialNetworkAccount:socialNetworkType=SKYPE;accountID=tsantalis
Basically my contact (which BusinessContact extends from) object has attributes of firstName, lastName and middleName,
it also has object attributes such as SocialNetworkAccount and such....
I don't need to be explained how my objects are formatted, those have been done all I'm trying to understand is how my file.txt in inputed into my program to set my Contact to a BusinessContact as well as setting the first and last name accordingly,
Thanks
EDIT: Im specifically told to use the split method which makes sense but I'm also told (1) create a common method for the parsing of attributes that returns a map where the keys correspond to the attributeNames and the values to the attributeValues (in this way you can reuse the same code)
You can use the Scanner class with different delimiters like below:
Scanner in = new Scanner(/**source*/);
in.useDelimiter(":");
String firstName, lastName;
String firstWord = in.next();
Scanner nameScanner = new Scanner(in.nextLine());
nameScanner.useDelimiter(";");
firstName = getName(new Scanner(nameScanner.next()));
lastName = getName(new Scanner(nameScanner.next()));
private String getName(Scanner nameScanner){
nameScanner.useDelimiter("=");
String nameTitle = nameScanner.next();
return nameScanner.next();
}
This way you read the text in parts as follows as follows:
BusinessContact:firstName=Nikolaos;lastName=Tsantalis
firstName=Nikolaos;lastName=Tsantalis
firstName=Nikolaos;lastName=Tsantalis
I hope this makes sense.
NOTE: This code reads only the first line. If you want to read the second i guess its not hard to modify it. If you want the second line too or if you have any issues let me know and i will update the answer.
EDIT: I just noticed that every line is formated the same way so basically you can use the same code for every line. Maybe in a loop like:
Scanner input = new Scanner(/**source*/);
while(input.hasNextLine()){
Scanner in = new Scanner(input.nextLine());
...
....
//The above code
}
String.split() method:
Scanner in = new Scanner(System.in);
String[] first = in.nextLine().split(":");
String[] second = first[1].split(";");
String[] thirdA = second[0].split("=");
String[] thirdB = second[1].split("=");
for(int i = 0; i < thirdA.length; i++){
System.out.println(thirdA[i]);
System.out.println(thirdB[i]);
}
For the first line, the above code will print:
firstName
lastName
Nikolaos
Tsantalis
Hope this helps.
You could use a regular expression, but you might feel more comfortable with String.split: Split on ":" and get the label, the split the second part on ";" to get the attributes, then split each attribute on "=" to get the key and the value.
I'd like to create a method where it can print out an array created by user's input in Scanner.
The data type of the array is double.
So far, I have created an array of the size that the user has provided, but how do I enter all the double input elements into an array then print it out in a method?
Do I need to ask the user to give each number one by one? I would like to avoid this. Thanks
If I understand what you are asking, you don't want hundreds of alert messages asking the user for input, correct? Just ask once?
If that is the case, you can ask the user to separate the input with some symbol. For example a semi-colon. Then the user can input something like this:
1;2;3;4;5
Then what you do is split the input to get the array, and you print it out using a for loop and a printing method of your choice (e.g. system.out or show in an alert message)
Hope that solves your problem
You could grab user input from the console, and have them separate entries with spaces... ie:
Enter your series separated by spaces:
123.33 333.44 342.22 43.33
Storing this result to a String and then passing it to this method.
public double[] setDoubleArray(String input, int arraySize) {
double[] doubleArray = new double[arraySize];
Scanner s = new Scanner(input);
for (int i = 0; s.hasNextDouble(); i++) {
doubleArray[i] = s.nextDouble();
}
s.close();
return doubleArray;
}
Is this what your looking for?
I have a data set that I wanted to read out and sort into arrays, the only problem is that all of the data is separated by spaces only.
I wanted to use loops to sort the data into a big multi-dimensional array, but since it's only separated by spaces I'm at a complete loss.
The data is sorted by a year followed by 6 spaces, then a month followed by three, then 31 sets of data for that month, each of which followed by 3 spaces. Like so:
1974 1 0.00 0.01
I'd wanted to do something like this:
while(year)
//sort into annual array
while(month)
//sort into monthly array
for(each individual data entry)
//sort each data entry into each month's array
Sorry if my wording isn't very good here. Many thanks in advance.
Probably best is to create a class for your data, then write a sort with a custom comparator.
You should use a Scanner to read in your data into your Data class, and store that in a List
public class MyData{
Date date;
float data[];
}
List<MyData> data = new ArrayList<MyData>();
/// add everything into data
Collections.sort(data, new Comparator<MyData>(){
#Override
public int compare(MyData data1, MyData data2) {
// compare on year
}
});
// Copy into new List
Collections.sort(data, new Comparator<MyData>(){
#Override
public int compare(MyData data1, MyData data2) {
// compare on month
}
});
/// keep sorting and copying
It seems that Scanner class is what you need here.
Scanner scanner = new Scanner(yourIntputStream);
Now write your loops that read your data using scanner.nextInt() or other methods provided by scanner. Check API doc for details.
You can use the "split"-method to transform the string into an array. E.g.:
String[] splittedString = yourString.split( ) // six spaces
Then split every ArrayEntry again by 3 spaces and so on.
Step one: Extract the data as an array by splitting on any number of whitespace:
String[] words = input.split("\\s+");
Step two extract the parts:
String year = words[0];
String month = words[1];
String [] data = Arrays.copyOfRange(words, 2, words.length);
This code caters for months with any number of days.
To obtain the 4 fields you can could use
String sInput = "1974 1 0.00 0.01";
String[] fields = sInput.split("\\s+");
where fields[0] will be the year, fields[1] the month, and so on.
If you want to work on the sorted data, probably you'll need to pre-load all the fields in another array, in a struct for the data.
I think your reading a fixed width file... can I suggest you look at fixedformat4j as mentioned in this answer Tactics for parsing fixed-width text log in Java
For a uni assignment, I have to take input from a text file and sort it into two separate arrays. The text file is a football league table, arranged as such:
Barcelona 34
Real Madrid 32
I have written a piece of code like this:
holdingString = fileInput.readLine ();
StringTokenizer sort = new StringTokenizer (holdingString + " ");
countOfTokens = sort.countTokens();
System.out.println (countOfTokens + " tokens: " + holdingString);
This prints out the number of tokens and what the tokens are for each line, so it gives output of
Two tokens: Barcelona 34
Three tokens: Real Madrid 32
I've then written this piece of code:
for (int i = 0; i < countOfTokens; i++)
{
String temp = sort.nextToken ();
System.out.println(temp);
}
This reads just the next token and prints it out.
However, rather than printing the next token out, I want to check if it is a word or a number, and separate it into a different array accordingly, so it will be like this:
ArrayTeam Zero Element Barcelona
ArrayTeam First Element Real Madrid
ArrayPoints Zero Element 34
ArrayPoints First Element 32
What's the easiest way to do this? I've tried using a try/catch, but didn't get it right. I've also tried using an if statement with \d, but that's not worked either.
Like AmitD, I agree that using split is more appropriate in this case, but if you still like to use a StringTokenizer you do something like:
StringBuilder teamName=new StringBuilder();
for (int i = 0; i < countOfTokens-1; i++)
{
if (i>0) teamName.append(' ');
teamName.append(sort.nextToken());
}
teamNames[k]=teamName.toString(); //add the new team to your teamNames array
points[k]=Integer.parseInt(sort.nextToken()); //if your points array is of int type
you could use java.util.Scanner class to read data from the file. it has methods such as nextInt(), nextDouble ...whhich might be useful in your case.
Scanner scan = new Scanner(file);
int number;
if(scan.hasNextInt()){
number = scan.nextInt();
}
check Scanner API
String readLine = "Real Madrib 40";
String[] team = readLine.split( "\\d" );
System.out.println(team[0]);
String score = readLine.replace( team[0],"" );
System.out.println(score);
Output :
team[0] : Real Madrib
score : 40
You can save all that trouble using split
String strs[] = holdingString.split("\\s");
E.g.
"Barcelona 34".split("\\s"); will return you Array of Strings where
array[0]=Barcelona array[1]=34
From Javadoc of StringTokenizer
StringTokenizer is a legacy class that is retained for compatibility reasons although its use is discouraged in new code. It is recommended that anyone seeking this functionality use the split method of String or the java.util.regex package instead.
Update
As #madhairsilence pointed out
You need another deliminator. You can use = like property files
"Real Madrid =34".split("=");//will return you Array of Strings where
array[0]=Real Madrid, array[1]=34
You can use Scanner as you are reading from file.