For-loop calculation of arbitrary times - java

I have a plain format txt file named enroll.txt which contains:
1997 2000
cs108 40 35
cs111 90 100
cs105 14 8
cs101 180 200
The first row shows the years of class
The second row first column shows the class name, and the following two columns show the number of students in the class in the years mentioned on the first row.
ex) In 1997, there were 40 students in class cs108.
My desired outcome: code prints as follows using
(i) split (ii) parseInt (iii) for-loop
student totals:
1997: 324
2000: 343
But this code should also work for any number of years (for example if I had student numbers for four years for each class instead of two, the code would still give me a similar output as below with student totals of say 1997, 2000, 2001, 2002 etc.)
What I have so far:
import java.util.*;
import java.io.*;
public class ProcessCourses{
public static void main(String[] args) throws FileNotFoundException{
Scanner console = new Scanner(System.in);
String fileName = console.nextLine();
Scanner input = new Scanner(new File(fileName));
while(input.hasNextLine()){
String line = input.nextLine();
String[] arr = line.split(" ");
//......????
}
}
}
What would go inside the //....????

So in the first line you have years, read them first :
Scanner input = new Scanner(new File(fileName));
String str = input.nextLine();
String[] years = str.split(" ");
Now you have set of student's information,
int[] total = new int[years.length];
while(input.hasNextLine()){
String line = input.nextLine();
String[] strength = line.split(" ");
int len = strength.length; // no of entries which includes course id + "years" no.of numbers.
for(int i=1;i<len;i++){ // from 1 because you don't care the course id
total[i-1] = total[i-1] + Integer.parseInt(strength[i]);
}
}
Then just print it :
for(int i=0;i<years.length;i++){
System.out.println(years[i]+ " : " + total[i]);
}

Related

Java scanner delimiter causes my integer to not be read properly

So I'm creating a scanner to read off of a simple text file:
import java.io.*;
import java.util.Scanner;
public class Weather {
public static void main(String[] args) throws FileNotFoundException {
int a;
File weatherData = new File("C:\\Users\\taddi\\eclipse-workspace\\COS_160_ASSIGNMENT_10\\src\\PortlandWeather1941to2018.txt");
Scanner scnr = new Scanner(weatherData);
scnr.useDelimiter("//");
int totalCount = scnr.nextInt();// this reads the number at the beginning and uses it so I know how many times to run the loop
String throwAway1 = scnr.nextLine();//these statement are used to throw a way the rest of line 1, and all of line 2 and 3
String throwAway2 = scnr.nextLine();
String throwAway3 = scnr.nextLine();
int[] month = new int[totalCount];
int[] day = new int[totalCount];
int[] year = new int[totalCount];
int[] tmax = new int[totalCount];
int[] tmin = new int[totalCount];
for(a = 0; a < totalCount; a ++) {
month[a] = scnr.nextInt();
System.out.println(month[a]);
day[a] = scnr.nextInt();
System.out.println(day[a]);
year[a] = scnr.nextInt();
tmax[a] = scnr.nextInt();
tmin[a] = scnr.nextInt();
}
}
}
The first part of the text file is an integer I'm trying to read. For some reason, it only reads that integer when I comment out the scnr.useDelimiter("//"); line, otherwise I get an InputMismatchException
I'd love to just get rid of all the unnecessary words and slashes in the text file but that wouldn't satisfy the assignment. What's going wrong with the delimiter? How do I read the integer?
Your delimiter is a string, and it will not work in your use case the way you want.
I assume your sample data is like this (ignoring the header lines) ...
01/01/1941 38 25
01/02/1941 32 20
... so you are looking to get each number - the date elements and the tmax/tmin values - so a single delimiter character of '/' would only break up the date.
For example:
final String data =
"01/01/1941 38 25 \n"+
"01/02/1941 32 20 \n";
Scanner scnr = new Scanner(data);
scnr.useDelimiter("/");
while(scnr.hasNext()) {
System.out.println(scnr.next());
}
scnr.close();
outputs the following ...
01
01
1941 38 25
01
02
1941 32 20
showing that it splits on the date d/m/y slashes, but the year and tmax and tmin are bundled together.
Adjusting the scanner to use a Pattern delimiter allows us to split on the slashes and the spaces.
final String data =
"01/01/1941 38 25 \n"+
"01/02/1941 32 20 \n";
Scanner scnr = new Scanner(data);
scnr.useDelimiter(Pattern.compile("[/ ]+"));
while(scnr.hasNext()) {
System.out.println(scnr.next());
}
scnr.close();
}
giving the output I think you want:
01
01
1941
38
25
01
02
1941
32
20
However, note that in my example data I have trailing whitespace on each line and they are thus also returned as empty String tokens. If I was scanning for nextInt() I would get an java.util.InputMismatchException error. Depending on the exact formatting of your input you may need to cater for that.

Reading from a CSV file parsing error/problem

Hello I am having issues reading from csv file which contains 3 columns per row. I cant seem to parse the last cell (3) to an integer even though it is always a "parsable" string:
Berlin,Buenos Aires,7402 I can't seem to get 7402 all the compiler throws is:
"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:68)
at java.base/java.lang.Integer.parseInt(Integer.java:658)
at java.base/java.lang.Integer.parseInt(Integer.java:776)
This is the code I have:
Scanner scan = new Scanner("worldcities.csv");
scan.useDelimiter("[,\\n]"); // get everything before a comma or a newline
while(scan.hasNext()) { // while this file has something then we
edge.v1 = scan.next(); // take vertice1 ----> city 1
edge.v2 = scan.next(); //take vertice2 ----> city 2
edge.e = Integer.parseInt(scan.next()); // parse the third value as int(distance between city1 and city2)
minheap.add(edge);
}
scan.close();
I seem to be able to get the first 2 values fine in the debugger.
the console just shows "
You can iterate throught file lines with the nextLine() method, as in this example:
Scanner scanner = new Scanner(new File("worldcities.csv"));
while (scanner.hasNextLine()) {
String columns[] = scanner.nextLine().split(",");
edge.v1 = columns[0]; // take vertice1 ----> city 1
edge.v2 = columns[1]; //take vertice2 ----> city 2
edge.e = Integer.parseInt(columns[2]); // parse the third value as int(distance between city1 and city2)
minheap.add(edge);
}
scanner.close();
or with using the Files class without the Scanner:
List<String> rows = Files.readAllLines(Paths.get("worldcities.csv"));
for (String row : rows) {
String columns[] = row.split(",");
edge.v1 = columns[0]; // take vertice1 ----> city 1
edge.v2 = columns[1]; //take vertice2 ----> city 2
edge.e = Integer.parseInt(columns[2]); // parse the third value as int(distance between city1 and city2)
minheap.add(edge);
}
Also you can use a special library for working with CVS files, for example look at Apache Commons CSV library.

Read multi line text file containing word and integer combinations, then calculate and display average

First time posting here, so please bear with me! I have a programming project due and I need help figuring out how to read through a text file (using a scanner) that contains multiple words and integers on a single line. The text file is a list of state names and their respective Average Family Incomes over a 3 year span. I need to get those values and calculate the average over the three years and display it all back in a nice table.
My problem is that I can get the average of the first few lines because they only have one word and three values. Using scanner.next() gets me past the first few lines, but there are multiple lines that contain 2 or more words and then the three values.
Currently, I get an InputMismatchException after the scanner reaches "District of Colombia" and it won't get the next value since scanner.next() only gets me to the word "of". Is there any way around this? Here is the first part of the project that just outputs all of the data (without an average):
Part 1 (works)
public class FamilyIncomeByState {
public void familyIncomeFile() throws IOException {
File income = new File ("src\\hw2p2\\FamilyIncome.txt");
Scanner scanner = new Scanner (income);
String year = scanner.nextLine();
System.out.println(year); System.out.println("--------------------------------------------");
while (scanner.hasNextLine()){
String line = scanner.nextLine();
System.out.println(line);
System.out.println(" ");
}
scanner.close();
}
}
Part 2 (doesn't work)
EDIT: Put in the wrong code the first time, this is the correct code.
public class AverageFamilyIncomeByState {
public void familyAverageIncomeFile() throws IOException {
File income = new File ("src\\hw2p2\\FamilyIncome.txt");
Scanner scanner = new Scanner (income);
String year = scanner.nextLine();
System.out.println(year + " Average");
System.out.println("-------------------------------------------------------");
while(scanner.hasNextLine()) {
String words = scanner.next();
double num1 = scanner.nextDouble();
double num2 = scanner.nextDouble();
double num3 = scanner.nextDouble();
double averageD = (num1 + num2 + num3) / 3;
BigDecimal average = BigDecimal.valueOf(averageD);
System.out.println(words + " " + average);
System.out.println(" ");
scanner.nextLine();
}
scanner.close();
}
}
And here is the content of the text file:
State 2002 2003 2004
Alabama 53754 54594 51451
Alaska 69868 71395 66874
Arizuna 56857 56067 55663
Arkansas 49551 47838 44537
California 65766 63761 63206
Colorado 68089 67634 66624
Connecticut 81891 82517 82702
Delaware 69469 73301 69360
District of Columbia 55692 61799 63406
Florida 57473 56824 55351
Georgia 60676 59497 59489
Hawaii 67564 66014 65872
Idaho 54279 51098 53722
Illinois 69168 66507 68117
Indiana 63022 63573 62079
Iowa 61238 61656 57921
Kanses 61926 61686 56784
Kentucky 54030 54319 51249
Louisiana 52299 51234 47363
Maine 58802 58425 56186
Maryland 77938 82879 77562
Massachusetts 78312 80247 78025
Michigan 67995 68337 68740
Minnesota 72379 72635 70553
Mississippi 47847 46810 46331
Missouri 59764 61036 61173
Montana 51791 48078 46142
Nebraska 60129 60626 57040
Nevada 59588 59283 59614
New Hampshire 72369 72606 71661
New Jersey 82406 80577 78560
New Mexico 48422 46596 47314
New York 65461 66498 64520
North Carolina 58227 56500 57203
North Dakta 57070 55138 53140
Ohio 63934 64282 62251
Oklahoma 51377 53949 48459
Oregon 60262 58737 58315
Pennsylvania 64310 66130 65411
Rhode Island 67646 70446 68418
South Carolina 56110 59212 56294
South Dakota 55359 59718 55150
Tennessee 55605 56052 54899
Texas 56278 56606 53513
Utah 59864 59035 57043
Vermont 62331 62938 59125
Virginia 66889 69616 68054
Warshington 66531 65997 63568
West Virginia 47550 49470 46270
Wisconsin 66988 65441 66725
Wyoming 57148 58541 55859
And here is my main method:
package hw2p2;
import java.io.IOException;
public class Launcher {
public static void main(String[] args) throws IOException {
FamilyIncomeByState familyIncomeByState = new FamilyIncomeByState();
familyIncomeByState.familyIncomeFile();
AverageFamilyIncomeByState familyAverageIncomeByState = new AverageFamilyIncomeByState();
familyAverageIncomeByState.familyAverageIncomeFile();
}
}
The part I'm stuck on should have an output that lists the Average values as a Fifth Column, but it just won't cycle past the 2nd word in a state name. Let me know if there's any more relevant information you need. Thanks!
This is just off the top of my head. But I think you should be able to use the split() function to split each line into strings separated by any white space. Then you can just take the last 3 strings in the array, converting each to an integer (or double) and then add those up. This way the number of words in the state is irrelevant.
int num1, num2, num3;
String[] tokens = scanner.nextLine().split("\\s+"); //split w/ delimeter
int length = tokens.length;
num 1 = Double.parseDouble(tokens[length - 1]); //last value of the array
num 2 = Double.parseDouble(tokens[length - 2]); //2nd last
num 3 = Double.parseDouble(tokens[length - 3]); //etc...
Hope this help! Let me know if you need any more clarification
sources:
whitespace delimeter:
How do I split a string with any whitespace chars as delimiters?
split function:
Splitting up data file in Java Scanner
By looking at the input format, I see that the columns are tab separated.
Use scanner.nextLine() to read the complete line, and then split the string on tab.
Hope it solves your issue
Since you said (in a comment) that the input file is tab separated you could use a StringTokenizer like this:
public void familyAverageIncomeFile() throws IOException {
File income = new File("src\\hw2p2\\FamilyIncome.txt");
Scanner scanner = new Scanner(income);
String year = scanner.nextLine();
System.out.println(year + " Average");
System.out.println("-------------------------------------------------------");
StringTokenizer tokenizer;
while(scanner.hasNextLine()) {
String words = scanner.nextLine();
tokenizer = new StringTokenizer(words, "\t");
String state = tokenizer.nextToken();
double num1 = Double.parseDouble(tokenizer.nextToken());
double num2 = Double.parseDouble(tokenizer.nextToken());
double num3 = Double.parseDouble(tokenizer.nextToken());
double averageD = (num1 + num2 + num3) / 3;
BigDecimal average = BigDecimal.valueOf(averageD);
System.out.println(words + "\t" + average);
System.out.println(" ");
}
scanner.close();
}
Output on my machine for the first few entries:
State 2002 2003 2004 Average
-------------------------------------------------------
Alabama 53754 54594 51451 53266.333333333336
Alaska 69868 71395 66874 69379.0
Arizuna 56857 56067 55663 56195.666666666664
Arkansas 49551 47838 44537 47308.666666666664
California 65766 63761 63206 64244.333333333336
Colorado 68089 67634 66624 67449.0
Connecticut 81891 82517 82702 82370.0
Delaware 69469 73301 69360 70710.0
District of Columbia 55692 61799 63406 60299.0
Hope this helps :) (Should work for the rest as well but a had to replace the tabs manually so I did only the first few and the one that caused your problem)

Exception in thread "main" java.util.NoSuchElementException: No line found

details:
Exception in thread "main" java.util.NoSuchElementException: No line found
at java.util.Scanner.nextLine<Scanner.java:1540>
at CarReader2.main<CarReader2.java:30>
that's the entirety of the error.
My code:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.*;
public class CarReader2 {
String name, speed, acc;
public CarReader2(String carName, String carSpeed, String carAcc){
name = carName;
speed = carSpeed;
acc = carAcc;
}
public String toString(){
return "Name of car: " +name+ "\nSpeed of car: " +speed+"\nAcceleration of car: " +acc+"\n";
}
public static void main(String[] args) {
File file = new File("carlist.txt");
try {
Scanner sc = new Scanner(file);
while (sc.hasNextLine()) {
String c1Name = sc.nextLine();
String c1Speed = sc.nextLine();
String c1Acc = sc.nextLine();
CarReader2 car1 = new CarReader2(c1Name,c1Speed,c1Acc);
car1.speed = c1Speed;
car1.acc = c1Acc;
String c2Name = sc.nextLine();
String c2Speed = sc.nextLine();
String c2Acc = sc.nextLine();
CarReader2 car2 = new CarReader2(c2Name,c1Speed,c1Acc);
car2.speed = c2Speed;
car2.acc = c2Acc;
System.out.println("Information on both cars");
System.out.println("First car:");
System.out.println(car1.toString());
System.out.println("Second car:");
System.out.println(car2.toString());
}
sc.close();
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
It's supposed to read data of 2 cars from a file called carlist.txt, then print the data of both cars in the correct format.
carlist.txt is a text file containing:
jonathan 3 7
dio 8 2
And the program is supposed to print out,
Information on both cars
First car:
Name of car: jonathan
Speed of car: 3
Acceleration of car: 7
Second car:
Name of car: dio
Speed of car: 8
Acceleration of car: 2
The program compiles but doesn't run correctly and shows the error i posted at the very top.
You're using nextLine method wrong. Name, speed and acceleration are in the same line, but you're using 3 nextLine methods to read them. That's what happens when you try to read 6 lines from a file that only has 2 lines in it. use sc.next() instead of sc.nextLine().
You are reading too many lines. There are only two lines in your file, but you are trying to read 6. You can change your text file to:
jonathan
3
7
dio
8
2
or you can read one line and split out the information you want.

Reading from a file, InputMismatchException

public static void main(String[] args) throws FileNotFoundException {
File file = new File("data.txt"); // select file
try{
Scanner sc = new Scanner(file); // set scanner to file
try{
while (sc.hasNextLine()){
Employee employee = new Employee(); //create employee to hold data
assignData(sc); //read data into employee
employee.getGross(); //calculate gross pay
addEmployee(employee);//assign employee to array
}//end while
}//end try2
finally {
sc.close(); // close file, saving resource usage
}//end finally
}//end try1
catch(IOException e) {
e.printStackTrace();
}
public static void assignData(Scanner input){
//accept scanner
//read necessary input for employee
EmpID = input.next();****
LastName = input.next();****
FirstName = input.next();****
(LINE 36)Hours = input.nextDouble();
Rate = input.nextDouble();
}
Data File contents
42345 Bruch Max 40 21.50
23456 Elgar Eddie 43 20.0
34567 Bach John 30 30
12345 Wagner Rick 41 30
88888 Mozart Wolfie 36 40
65432 Chopin Fred 45 23.25
72345 Strauss Butch 50 25
compiling, i get the error
"Exception in thread "main" java.util.InputMismatchException
at java.util.Scanner.throwFor(Scanner.java:909)
at java.util.Scanner.next(Scanner.java:1530)
at java.util.Scanner.nextDouble(Scanner.java:2456)
at programassignment1c.Employee.assignData(Employee.java:36) (
at programassignment1c.ProgramAssignment1C.main(ProgramAssignment1C.java:44)
Java Result: 1
Line 36 in Employee class, is highlighted above, it is the nextDouble() What am i doing wrong? Can doubles be scanned for even if they have no decimal place?
Writing this out by hand I see the scanner starting on: 42345 and it sets this to EmpID, then scanner advances past whitespace to
Bruch and it sets this to LastName, then scanner advances past whitespace to Max and it sets this to FirstName, then scanner advances past whitespace to 40 and should set this to Hours???? i am not following the scanner correctly?
I believe you need to use specific data type methods here :
EmpID = input.nextLine();
LastName = input.nextLine();
FirstName = input.nextLine();
try using nextInt/next instead of nextLine.As nextLine will read the entire line and when you try to assign it to an int value it throws InputMismatchException.
nextLine() won't fit in your requirement(because data in the file is separated by space not the new line).
Since It advances this scanner past the current line and returns the input that was skipped. This method returns the rest of the current line, excluding any line separator at the end. The position is set to the beginning of the next line.
So try this
public static void assignData(Scanner input)
{
empID = input.nextInt();
lastName = input.next();
firstName = input.next();
hours = input.nextDouble();
rate = input.nextDouble();
}
Note: I have changed your variables names to follow java naming convention.
You are calling nextLine() instead of next() which reads (and skips but doesn't consume line separators) the line each time. You have
EmpID = input.nextLine();
LastName = input.nextLine();
FirstName = input.nextLine();
(LINE 36)Hours = input.nextDouble();
Rate = input.nextDouble();
So
42345 Bruch Max 40 21.50 // EmpID
23456 Elgar Eddie 43 20.0 // LastName
34567 Bach John 30 30 // FirstName, but not the new line characters
12345 Wagner Rick 41 30
88888 Mozart Wolfie 36 40
65432 Chopin Fred 45 23.25
72345 Strauss Butch 50 25
See comments.
The javadoc for nextLine() states
This method returns the rest of the current line, excluding any line
separator at the end.
so the nextDouble() call is trying to read the line separator which isn't of type double and so throws an InputMismatchException.
You want each token on the line, use
EmpID = input.next();
LastName = input.next();
FirstName = input.next();
Hours = input.nextDouble();
Rate = input.nextDouble();
The javadoc for next() states
Finds and returns the next complete token from this scanner. A
complete token is preceded and followed by input that matches the
delimiter pattern.
where the delimiter by default is
Pattern.compile("\\p{javaWhitespace}+");
ie. whitespace characters.
Java naming conventions dictate that variable names should start with a lowercase alphabetic character.

Categories