Finding end of file in Java - java

I have a method that loops through a file to find the number of lines.
static int findFileSize(Scanner f){
System.out.println("Got to counter:");
String str;
int line_count = 0;
while(f.hasNextLine()) {
line_count++;System.out.println(line_count);
//str = f.nextLine();
}System.out.println("File size: " + line_count);
return line_count;
}//end findFileSize
When i don't include the str = f.nextLine();, i can see it indexing indefinitely. What causes this to happen? And is there a way of finding the number of lines in a .txt file without needing to unnecessarily store a data into a string?

What causes this to happen?
You aren't reading anything from the Scanner, you're just asking it if you will be able to read something.
If you walk into a shop and ask if they have, say, carrots, if the answer is "yes", but you don't buy any carrots, the shop still has carrots. So, if you walk out and walk in to ask again, they will still have the carrots, so they will again answer "yes" (unless somebody else has bought them).
You have to "buy the carrots" by using f.nextLine().
without needing to unnecessarily store a data into a string?
You don't have to store it in a variable:
f.nextLine();
will read the String and immediately discard it. But there isn't really a huge difference between this and storing it in a variable: the variable only keeps the contents of the last-read line anyway. (But since you don't give str an initial value, it's not definitely assigned after the loop, so you can't read its value after the loop in any case).

Related

Read line until int is met java

If i have the following input:
sometext 23,1 -54.2 42
sometext 42,6 32 -56
How do i read firstly only the string and then the numbers.
for(int i = 0 ; i < numLines ; i++){
name = scanner.nextLine() // Here i want to save "sometext"
for(int j = 0 ; j < numNumbers ; j++){
numbers.add(scanner.nextFloat());
}
cities.add(new City(name, numbers));
numbers.clear();
}
Generally, don't ever call nextLine. It doesn't do what you think it does, and what it does do, is almost entirely useless. Yes, it shows up in every tutorial under the sun.1
Just call .next() if you want a string.
Thus, here, you should be invoking next() to read strings, and nextDouble to read doubles. Except you have utterly bizarre input, where sometimes commas show up and sometimes dots, to separate inputs. Did you make a typo when copying this over? If this is indeed your input, you can only use next(), and then you ahve to massage this broken crazy input first before turning it into numbers.
Also, you don't ever want to use float either. Just use double2. For everything. No it is not 'less efficient' or 'takes more memory'. It's just better, for free.
That was a typo, the input is consistent.
Ensure the scanner has the proper locale set, otherwise it will be expecting a , as separator instead of a . or vice versa. Failure to set locale means that your app will randomly not work depending on the configuration of the host system you're on, you usually do not want that. Use scanner.useLocale(Locale.ENGLISH) for example to do this.
Then:
name = scanner.next(); // returns "sometext"
for (int j = 0; j < numNumbers; j++) {
numbers.add(scanner.nextDouble());
}
It really is that mixed crazy
Then instead of .nextDouble:
String raw = scanner.next();
raw = raw.replace(",", ".");
numbers.add(Double.parseDouble(raw));
You also have a bug
Java is pass-by-value, but numbers is a reference. It's like me handing you, on a note, an _address to a building, and then me driving over there and burning the place to cinders. It doesn't matter that the address I gave you was written on a copied piece of paper you drove off with. If you follow your personal copy of that address, you still find a burnt out house.
So, when you write numbers.clear(), you're removing the numbers from that newly created city. What you want instead of numbers.clear(), which is java-ese for: "Take the piece of paper that you named numbers, which has an address written on it. Drive over there. Burn the house down.", and replace it with: numbers = new ArrayList<Double>() which is java-ese for: "Build a new house on a free spit of land. Take your piece of paper called numbers, and erase whatever is written on there. Now jot down the address to this newly built house.".
You want the second thing. Remember, . is java-ese for: Drive to the address written on here, and = is: Mess with the address itself, do not drive anywhere.
1] You don't need to follow this reasoning to use Scanner, but for those who'd like to know why I say this: Mixing nextLine and nextAnythingElse causes the dreaded problem where you generally just get an empty string back with nextLine. You can invoke a 'blank' nextLine (don't assign it to anything), but then your input processing is broken if the user ever hits that really big, centrally placed key on their keyboard, so that seems like a bad move, even if it is common advice. The real solution is to update the delimiter to \\R, but once you've done that, you don't need nextLine to read lines, just next will do it. Using only nextLine does work fine, but if that's what you want, just.. make a BufferedReader instead, Scanner is overkill. Conclusion: There are no scenarios where nextLine ever makes sense.
2] If some protocol explicitly says to use float, or you know all about IEEE style floating point numbers, you know enough to know when you can ignore this advice. Until you do, heed it.
This code will do the trick:
for(int i = 0 ; i < numLines ; i++){
name = scanner.next();
for(int j = 0 ; j < numNumbers ; j++){
numbers.add(scanner.nextFloat());
}
cities.add(new City(name, numbers));
numbers.clear();
}

ArrayList<Integer> is not storing user-inputted integers in Java 8 (1.8)

*EDIT - SOLVED: After instantiating the Scanner Object, I used a delimiter as follows:
scanner.useDelimiter("");
Prior to this, I did try a delimiter that looked something like this (the exact code is available on Stack Overflow):
scanner.useDelimiter("\\p{javaWhitespace}");
...but it didn't work very well.
Thank you, everyone. If you're having this very same issue, try the first delimiter. If it doesn't work, upgrade your JDK to 13 then try it again.
Ok, my goal is to have a user input a credit card number which I would then like to store in an ArrayList of Integers and subsequently pass this list to my functions which will perform the Luhn algorithm in order to validate the provided number. Once the user presses Enter, the processing begins. This is a console application, nothing fancy.
Everything works beautifully...except the user-input part. None of the user-input is being stored into the declared ArrayList. I've inserted a print message to give me the size of the list just after the pertinent while-loop and....yep, 0. I also pass this list into a custom lengthChecker(ArrayList<Integer> list){} function subsequent to the relevant while-loop and it's printing my custom error-message.
I have declared local int variables within the scope of the while-loop and that wasn't helping much. I have tried getting the user's input as Strings and storing them in an ArrayList<String> list; then parsing the input but that didn't work very well (especially as I need the Enter key to behave as a delimiter such that the next steps can take place)
Anyways, here is the code to the function in question. Am I missing something obvious or should I just quit programming?
public void userInput() {
Scanner scanner = new Scanner(System.in);
List<Integer> list = new ArrayList<Integer>();
System.out.println("Please input the card-number to be checked then press Enter: ");
while(scanner.hasNextInt()) {
list.add(scanner.nextInt());
}
System.out.println("Length of list: " + list.size());
listLengthChecker(list);
scanner.close();
}
Thank you in advance.
I don't have the full context on all the code you've written to be able to solve your problem, but I can guess at what's going on. If you want to run any user I/O (such as the scanner), it must occur within the main method. I can only assume that you run your userInput() function within the main method in your class. However, because your userInput() function doesn't have the static keyword in its definition, it can't be accessed without initialising an object of the class - but as far as I can tell from your code, there is no object that the method could refer to. Add the static keyword (i.e. initialise the method as public static void userInput()) to be able to run the function as you intend.
As for the while loop - there's a small chance that this is a difference in Java versions (I use Java 11), but while(scanner.hasNextInt()) won't stop being true at the end of your line or when you press enter - only when you insert something (such as a character) that cannot be interpreted as an integer.
This while loop untill you enter any non integer value.
You finished entering all the integer values and then your program will print your list elements.

JAVA : Performance and Memory improvement code comparison from codechef

So today I solved a very simple problem from Codechef and I solved the problem using JAVA my answer was accepted. My code was.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
class INTEST {
public static void main(String args[]) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String input = reader.readLine();
int n = Integer.parseInt(input.split(" ")[0]);
long k = Long.parseLong(input.split(" ")[1]);
int count = 0;
String element;
for (int i = 0; i < n; i++) {
element = reader.readLine();
if (Long.parseLong(element) % k == 0) {
count++;
}
}
System.out.println(count);
}
}
The onine judge reported
Running Time : 0.58 Second
Memory : 1340.5M
So, I looked into some other solutions for the same problem (sorted the solution by time) and I got another solution by the user indontop.
public class Main{
public static void main(String ...args)throws Exception{
byte b;
byte barr[]=new byte[1028];
int r=0,n=0,k=0;
while((r=System.in.read())!= ' '){
n=n*10+r-'0';
}
//System.out.println(n);
while((r=System.in.read())!='\n'){ //change
k=k*10+r-'0';
}
//System.out.println(k);
//System.in.read(); // remove
n=0;
int count=0;
while((r=System.in.read(barr,0,1028))!=-1){
for(int i=0;i<barr.length;i++){
b=barr[i];
if(b!='\n'){ //change
n=n*10+b-'0';
}
else{
// i++; //remove
if(n%k==0)count++;
n=0;
}
}
}
System.out.println(count);
}
}
the execution time and memory for the above code.
Running Time : 0.13 Second
Memory : OM
I wonder how was the user able to achieve this much performance and Memory gain with this very simple problem.
I dont understand the logic behind this code, can anyone help me by explaining this code, and also please explain what is wrong with my code.
Thank You.
How indontop achieved a better memory footprint
Basically, indontop's program reads bytes directly from the input stream, without going through readers or reading lines. The only structure it allocates is a single array of 1028 bytes, and no other objects are created directly.
Your program, on the other hand, reads lines from a BufferedReader. Each such line is allocated in memory as a string. But your program is rather short, so it's highly likely that the garbage collector doesn't kick in, hence all those lines that were read are not cleared away from memory.
What indontop's program does
It reads the input byte by byte and parses the numbers directly from it, without using Integer.parseInt or similar methods. The characters '0' through '9' can be converted to their respective values (0-9) by subtracting '0' from each of them. The numbers themselves are parsed by noting that a number like '123' can be parsed as 1*10*10 + 2*10 + 3.
The bottom line is that the user is implementing the very basic algorithm for interpreting numbers without ever having the full string in memory.
Is indontop's program better than yours?
My answer to this is no. First, his program is not entirely correct: he is reading an array of bytes and is not checking how many bytes were actually read. The last array read can contain bytes from the previous read, which may give wrong output, and it is by sheer luck that this didn't happen when he ran it.
Now, the rest of this is opinion-based:
Your program is much more readable than his. You have meaningful variable names, he doesn't. You are using well-known methods, he doesn't. Your code is concise, his is verbose and repeats the same code many times.
He is reinventing the wheel - there are good number parsing methods in Java, no need to rewrite them.
Reading data byte-by-byte is inefficient as far as system calls are concerned, and improves efficiency only in artificial environments like CodeChef and like sites.
Runtime efficiency
You really can't tell by looking at one run. Those programs run under a shared server that does lots of other things and there are too many factors that affect performance. Benchmarking is a complicated issue. The numbers you see? Just ignore them.
Premature Optimization
In real world programs, memory is garbage collected when it's needed. Memory efficiency should be improved only if it's something very obvious (don't allocate an array of 1000000 bytes if you only intend to use 1000 of them), or when the program, when running under real conditions, has memory issues.
This is true for the time efficiency as well, but as I said, it's not even clear if his program is more runtime efficient than yours.
Is your program good?
Well, not perfect, you are running the split twice, and it would be better to just do it once and store the result in a two-element array. But other than that, it's a good answer to this question.

Java- Scanner is not reading String properly

I am writing a program for a school project in which I read a .csv file and perform calculations based on the data within it.
System.out.println("Please enter a second data set to search:\nFor example, type 'narcotics, poss,' 'criminal damage,' or 'battery.'\nCapitalization does not matter.");
secondDataSet = scan.nextLine().toUpperCase();
System.out.println("Searching for instances of " + secondDataSet);
if (!secondDataSet.equals(""))
{
while (inputStream.readLine() != null)
{
String[] all = line.split(splitBy);
if (all[8].toUpperCase().equals("TRUE"))
{
numArrests++;
}
if (all[8].toUpperCase().equals("FALSE"))
{
numNonArrests++;
}
if (all[5].equals(secondDataSet))
{
secondDataCount++;
}
numberOfLines++;
line = inputStream.readLine();
}
if (secondDataCount == 0)
{
i--;
System.out.println("The data set you entered does not exist.\nPlease try checking your spelling or reformatting your response.");
}
The above is part of my code I am using that contains my Scanner problems. I am reading a .csv containing the Chicago arrest records for the past several years. Every time I run the program, however, it skips past the scan.nextLine(). It just executes my print statement "Please enter a second data set..." and then prints out "Searching for instances of ".
I am using jGRASP, and my compiler looks like:
Please enter a data set to search:
For example, type 'narcotics, poss,' 'criminal damage,' or 'battery.'
Capitalization does not matter.
Searching for instances of
And it loops four times without getting user input. I tried using scan.next() instead, but that did not work when I input a String with two words because some there are some values in the .csv like "CRIMINAL DAMAGE" and scan.next() searched for the words "CRIMINAL" and "DAMAGE" separately. If someone has any suggestions on how to make the computer stop to read the scan.nextLine(), use scan.next() to read two words, or any other solution to this I would appreciate it.
I am extremely confused by this at the moment so any help would be very nice as I've spent an enormous amount of time on a small part of a large project that I need to complete... Also, I can clarify any questions you may have if my question is unclear or vague.

Best approach for storing three teirs of data - multi-d array?

I'm operating on a file that has this kind of format:
LAWS303 RHLT1 10 84 AITKEN WU
LAWS314 RHLT3 15 2 PARADZA VISSER
LAWS329 EALT006 6 62 AITKEN WILSON
LAWS334 HMLT105 2 43 ANDREW INKSTER
LAWS334 HMLT206 2 62 JULIAN YOUNG
LAWS340 RHLT1 11 87 AL YANG
The goal of this program is that for each day (the third column) of the month, each course code (first column) should be printed along with the total number of students attending (fourth column) for the course on that day. From my thinkering, this involves either reading the file a lot of times (ew!) or loading the three salient values (day, course, headcount) into some sort of array and operating on that instead. Despite being fairly familiar with what a multi dimensional array is, this one has repeatedly caused my head to implode. I've got the pseudo code for this program written out in front of me and my mind draws a blank when it comes to the line that defines the array.
The dayOfMonth can remain a string because it'll only be compared to another string. The courseCode obviously needs to be a string, too. However, the headCount ideally would be numeric; it'll be added to as each line of the file is processed. The relationship between the three is basically that there can be many courseCodes per dayOfMonth, but only one headCount per courseCode as I'll be adding to it as I read it all into the array.
So, in derpspeak, this is how it should roughly look:
{String dayOfMonth = {{String courseCode}, {int headCount}}}
The two issues I have here, are...
a) that I'm not sure how to actually code this kind of funky array in there and
b) as I can't really wrap my brain around it to begin with, there's a really good chance that I've essentially just designed something completely wrong for what I need. Or impossible. Both?
For example, the array will start off empty. I'd want to add a dayOfMonth, courseCode and headCount to start it off. But I couldn't just go array.add(dayOfMonth) because it's expecting an array, leading me to suspect I should be using something else. Argh!
Oh god my brain.
This looks like homework, so my answer will consist of hints.
Hint #1 - there are some entities in those rows. Work out what they are and write a class for each one.
Hint #2 - Use List types not arrays. Arrays have to be preallocated with the right number of elements.
Hint #3 - Use Map types (e.g. HashMap or TreeMap) to represent mappings from one kind of thing to another kind of thing.
If you want to store and retrieve the values then use #Stephan C's input.
Here is code snippet to print values using sysout. You can modify to hold the values as you wish.
BufferedReader reader = new BufferedReader(new FileReader("< your file here >"));
String string = reader.readLine();
while (string != null) {
StringTokenizer tokenizer = new StringTokenizer(string);
String print = "";
if (tokenizer.countTokens() > 4) {
print = tokenizer.nextToken();
tokenizer.nextToken();
print = tokenizer.nextToken() + " " + print;
print = print + " " + tokenizer.nextToken();
}
System.out.println(print);
string = reader.readLine();
}

Categories