Line Not Found on while loop? - java

I've been trying to get this to work for a while. I'm putting in three parallel empty arrays and it errors out saying that there is no line found. It ONLY works when I change the while statement to the number of elements. I am trying to make arrays that are the size of 15, but only fill the first ten array portions.
Sorry if it sounds complicated, but basically I'm trying to say that the size of the array is 15, I only have 10 things to enter in the array, and the rest of them should be blank.
while (text.hasNext() && c < nameArray.length) {
nameArray[count] = text.nextLine();
intArray[count] = text.nextDouble();
doubleArray[count] = text.nextInt();
text.nextLine();
c++;
}
This does not work.
while (text.hasNext() && c < 9) {
nameArray[count] = text.nextLine();
intArray[count] = text.nextDouble();
doubleArray[count] = text.nextInt();
text.nextLine();
c++;
}
This does.

Your read the file TWICE within a single loop. Remove the 2nd read:
fileText.nextLine();

Of course it doesn't work. If you need to cycle to the max between fileText length and gameArray length, you should use or instead of and and use an if in the loop.
Try something like this:
while (fileText.hasNext() || count < gameArray.length) {
if (!fileText.hasNext()) {
gameArray[count] = "";
priceArray[count] = 0;
stockArray[count] = 0;
} else {
gameArray[count] = fileText.nextLine();
priceArray[count] = fileText.nextDouble();
stockArray[count] = fileText.nextInt();
fileText.nextLine();
}
count++;
}

Your issue is not with the length of the array but with fileTest.nextLine(). After a certain point there is no nextLine() available. It works for the 1st 9 times but I guess all the lines are exhausted before you reach array.length. I would suggest just one condition in your while loop:
while(fileText.hasNext()) {
}
This way you would fill in only the amount actually present.

Add another check with the second fileText.nextLine() to ensure that there is a line to read.
while (fileText.hasNext() && count < gameArray.length) {
gameArray[count] = fileText.nextLine();
priceArray[count] = fileText.nextDouble();
stockArray[count] = fileText.nextInt();
if ( fileText.hasNext() )
fileText.nextLine();
count++;
}

In the first version of your code, your try to read input 15 times, but it is entered only 10 times. So the scanner tries to read a new line but it doesn't exist.

Related

How to add a variable to another variable that's already set

My homework is to create a program that takes a list of numbers and prints out the highest number divisible by four.
List would look like this:
12
16
87
58
25
73
86
36
79
40
12
89
32
Input should be:
40 because it is the highest number there divisible by four.
Here is my code:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int saved = 0;
int saved2 = 0;
for (int i = scanner.nextInt(); i % 4 == 0; i = scanner.nextInt()) {
for (boolean bull = true; bull == true; bull ^= true) {
if (i > saved) {
saved -= saved2;
saved += i;
saved2 += i;
}
}
System.out.println(saved);
}
}
}
The input of my code is
12
16
I don't really understand why this is doing it, but it seems to me that I'm adding the variables wrong. The homework page on adding variables does not specify how to add variables to each other.
Does anyone have a tip to improve the code in anyway, or find a way to make a fix my code? Thank you.
welcome to Java.
First you are saying you got input, but that is output. Input is what you enter, and output is what you get printed.
Then there is a mistake in your for loops. You have too much going on in one place. By the logic which is implemented, your program will exit first level for loop whenever your entered value is not divisable by 4.
Read on for loops if you want to learn more https://www.learnjavaonline.org/en/Loops.
I recommend to start from while loops instead. The logic whould be this:
1. create variable to hold the correct answer saved
2. create another one to hold the value read from console i
3. start the while loop with condition i = scanner.nextInt()
3.1 check if the value just entered i is divisable by 4
3.2 if it is, then compare if it's larger than the one was saved before (initially saved value will be 0)
3.3 if it is larger, then assign the read value i to the saved
4. At the end of the loop, you will have the highest number divisable by four in your saved variable. Print it.
I will provide some help, according to
How do I ask and answer homework questions?
for (int i = scanner.nextInt(); i % 4 == 0;i = scanner.nextInt())
This only reads as long as ALL inputs are divisible by 4, that is why it ends at 16, because 87 is not divisible by 4.
for (boolean bull = true; bull == true ;bull ^= true)
This needs explanation by you, but I am pretty sure that it unconditionally executes the body of the inner loop exactly once. (Not 100% sure, because the representation of true and false could be weird in your machine. Should 0 be the representation of true, i.e. really weird, then it is an endless loop, which does not match the output you describe...)
System.out.println(saved);
This executes exactly once per input, except the last one, which is not a multiple of 4.
The value of saved is identical to input, as long as it is increasing.
These hints explain the unexpected output.
If you inspect the details of what the problem is, you should be able to improve your coding attempt.
This is how I super-quickly fixed in your code.
Note that there are no statements about the possible minimum value and about how do you stop the input. Therefore the solution is pretty-straightforward, it just reads the input until integers are present there.
This article may be useful about handling the input from the Scanner.
I hope the comments in the code will help. Add comments if there are any questions. Good luck!
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int currentMax = Integer.MIN_VALUE; // you may set negative or 0 if you know that all the input is positive
// int saved2 = 0; // no need for this variable
while (scanner.hasNextInt()) { // you can make a better input handling, especially if you know when it should end the input. Now it will end on any non-integer input line
int i = scanner.nextInt();
// for (int i = scanner.nextInt(); i % 4 == 0; i = scanner.nextInt()) {
// for (boolean bull = true; bull == true; bull ^= true) {
if (((i % 4) == 0) && (i > currentMax)) {
currentMax = i;
// saved -= saved2;
// saved += i;
// saved2 += i;
// }
}
}
System.out.println(currentMax); // moved out of "for" or "while" cycles. Print the value after the input has ended.
}
}

Cut out different elements from a string and put them into a list

Here's updated code. For those following along the question edits contains the original question.
if (0 != searchString.length()) {
for (int index = input.indexOf(searchString, 0);
index != -1;
index = input.indexOf(searchString, eagerMatching ? index + 1 : index + searchString.length())) {
occurences++;
System.out.println(occurences);
indexIN=input.indexOf(ListStringIN, occurences - 1) + ListStringIN.length();
System.out.println(indexIN);
System.out.println(ListStringIN.length());
indexOUT=input.indexOf(ListStringOUT, occurences - 1);
System.out.println(indexOUT);
Lresult.add(input.substring(indexIN, indexOUT));
System.out.println();
}
}
As you can see, I gave me out the index numbers
My code works well with only one Element
But when I write something like this: %%%%ONE++++ %%%%TWO++++
There's this exception:
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: begin 16, end 7, length 23
at java.base/java.lang.String.checkBoundsBeginEnd(String.java:3410)
at java.base/java.lang.String.substring(String.java:1883)
at com.DMMS.Main.identify(Main.java:81)
And I found out that the indexIN changes in the Start of the second String but not the indexOUT
I couldn't find out why
When you look at your code you can notice: in the first loop that counts the number of occurrences, your code "knows" that it has to use that version of indexOf() that relies on offsets within the search strings.
In other words: you know that you have to search after previous "hits" when walking through your string.
But your second loop, the one that has to extract the actual things, there you are using indexOf() without that extra offset parameter. Therefore you keep "copying out" the same part repeatedly.
Thus: "simply" apply the same logic from loop 1 for loop 2!
Beyond that:
you don't need two loops for that. Counting occurrences and "copying out" the matching code ... can be done in one loop
and honestly: rewrite that first loop. This code is almost incomprehensible for human beings. A reader would have to sit down and read this 10, 20 times, and then run it in a debugger to understand what it is doing
I dit it!
Heres the code:
.........................
static String ListStringIN = "%%%%";
static String ListStringOUT = "++++";
........................
else if (input.contains(ListStringIN) && input.contains(ListStringOUT)) {
System.out.println("Identifiziere Liste...");
String searchString = ListStringIN;
int occurences = 0;
boolean eagerMatching = false;
if (0 != searchString.length()) {
for (int index = input.indexOf(searchString, 0); index != -1; index = input
.indexOf(searchString, eagerMatching ? index + 1 : index + searchString.length())) {
occurences++;
System.out.println(occurences);
indexIN=input.indexOf(ListStringIN, occurences - 1) + ListStringIN.length();
System.out.println(indexIN);
//indexOUT=input.indexOf(ListStringOUT, occurences);
//indexOUT=input.indexOf(ListStringOUT, occurences - 1);
indexOUT = input.indexOf(ListStringOUT, eagerMatching ? index + 1 : index + ListStringOUT.length());
System.out.println(indexOUT);
Lresult.add(input.substring(indexIN, indexOUT));
System.out.println();
}
}
//for (int i = 0; i <occurences; i ++) {
// Lresult.add(input.substring(input.indexOf(ListStringIN, 0) + ListStringIN.length(), input.indexOf(ListStringOUT)));
//}
result = Lresult.toString();
return result;
}
I hope this is useful for other people
#GhostCat Thanks for your advices!

Why do I need to use count -=1 in the following code?

When creating the following function, in order to get a correct answer I have to add "count-=1" line, otherwise the answer gets skewed by 1.
public int countCTG(String dna) {
int count = 0;
int firstOccurrence = dna.indexOf("CTG");
if (firstOccurrence != -1) {
count +=1;
while (dna.indexOf("CTG", firstOccurrence) != -1 && firstOccurrence != -1) {
count +=1;
firstOccurrence = dna.indexOf("CTG", firstOccurrence+3);
}
count -=1;
}
else {
count = 0;
}
return count;
}
I managed to get this function working, however could you please help me understand the logic behind it? The count variable was initialized originally to 0 and if a string,for example, contains one instance of "CTG" it will be already counted in by "count +=1" line. Wouldn't count -=1 reset this variable back to 0?
You need the -1 because of the +1 before the loop: the first iteration of the while loop counts the already-found occurrence again.
An easier solution is like so:
int count = 0;
int skip = "CTG".length();
int current = -skip;
while ((current = dna.indexOf("CTG", current + skip)) >= 0) {
++count;
}
return count;
Because you're not updating firstOccurrence after your first search -- i.e. you're searching twice from the start (.indexOf("CTG")) before starting to search from the previous result (.indexOf("CTG", prevResultIndex + 3)).
Also note that:
you don't have to search once before the while loop
the else clause is redundant
you're calling .indexOf twice as many times as you actually need
the firstOccurrence+3 is a liability, you'll forget to update the offset when the string changes and it will be hard to track down. Store the searched-for string in one place, and compute its length instead of hardcoding it.
EDIT: Well #AndyTurner rewrote it for you, but try to see how each one of the listed points come into reaching that result

Java add line to specific part of text file

COMMENTS BELOW ARE ANSWERING ANOTHER QUESTION, THIS IS THE ONLY WAY FOR ME TO ASK NEW QUESTION...
Okay. My program is like writing info on a .txt file. Currently it is writing info to end of the text file like so:
t/1/15/12
o/1/12/3
o/2/15/8
... (lots of lines like this.. all with different numbers)
o/1/16/4
Then.. when I add line using:
BufferedWriter fw = new BufferedWriter(new FileWriter(new File("C://Users/Mini/Desktop/Eclipse/Japda/map/" +Numbers.map +".txt"), true));
fw.newLine();
fw.write(RightPanel.mode.charAt(0) +"/" +ID +"/" +Numbers.middlex +"/" +Numbers.middley);
fw.close();
It adds the line I want to but currently to the end of the text file.. However I would like it to write that line to a specific part of the text files.. I already do know the number of the line I want to write it.. (It is calculated depending on other lines..) :D Is there any way to do it? Or what would be the best way to edit one specific line in the middle of that text file?
To achieve what you require, you would need to use a RandomAccessFile. Steps:
First create a RandomAccessFile then:
Create a variable called lineStart which is initially set to 0
(beginning of the file)
Read in the file line by line using readline
Check whether it is the required line that you wish to insert before
If it is the correct place, then lineStart will hold the position
just before the line you wish to insert before. Use seek to
position you at the correct place by initially using seek(0) to
position you at the start of the file, then seek(lineStart) to get
the required position. You then use writeChars to write to the file.
Remember that you have to explicitly write the newline.
If it is not where you wish to insert then call getFilePointer, and
store value in lineStart
REPEAT STEPS 2-5 UNTIL YOU ARRIVE AT THE DESIRED PLACE FOR INSERTION
You want a do-while loop:
do {
//code
} while (expression);
Source:
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/while.html
You probably want something like this:
int[] done = new int[100];
int randomquestion;
do{
randomquestion = (int)(Math.random() * 83 + 1);
if(done[randomquestion] != 1)
{
//ask random question
//if answer is correct, set done[randomquestion] = 1
//else just let do-while loop run
}
//check if all questions are answered
} while (!areAllQuestionsComplete(done));
Here is the method areAllQuestionsComplete(int[]):
private boolean areAllQuestionsComplete(int[] list)
{
for(int i = 0; i<list.length; i++)
{
if(list[i] != 1)
{
return false;//found one false, then all false
}
}
return true;//if it makes it here, then you know its all done
}
Looking at your latest code:
for(int i = 0; i<done.length; i++)
{
done[i] = 0;//need default values else wise itll just be NULL!!!
}
do{
ran = (int)(Math.random() * 83 + 1);
//before entering the do-while loop, you must set default values in the entire done[] array
if(done[ran] != 1)
{
//ask random question
//if answer is correct, set done[ran] = 1
//else just let do-while loop run
if (ran == 1) { //1
question = "kala";
rightanswer = "fish";}
if (ran == 2) { //2
question = "peruna";
rightanswer = "potato";}
if (ran == 3) { //3
question = "salaatti";
rightanswer = "cabbage";}
if (ran == 4) { //4
question = "kalkkuna";
rightanswer = "turkey";}
if (ran == 5) { //5
question = "kia";
rightanswer = "tikku";}
//YOU MUST HAVE EVERY CONDITION COVERED
//say your random number makes the number 10
//you dont set question to anything at all (hence getting null!)
System.out.println(question);
System.out.print("Vastaus?: ");
answer = in.readLine();
//if (answer == rightanswer){
//must use .equals with Strings...not ==
if (answer.equals(rightanswer)){
right++;
done[ran] = 1;}
else{wrong++;}
}
//check if all questions are answered
} while (!areAllQuestionsComplete(done));//use the method I wrote!
EDIT:
You must put default values in the array. When you create an array, the default value is null.
int[] done = new int[100];//create array but everything is null
for(int i = 0; i<done.length; i++)
{
done[i] = 0;//need default values else wise it'll just be NULL!!!
}
//must be done before the do-while loop starts
Finally, make sure your random number generator picks the correct range in numbers. If you have an array that is size 100, then it's indexes will be 0-99. This means there is no done[100]. It goes from done[0] to done[99].
If you have done[] be a size of 5, then it will range from done[0] to done[4]. That means you should randomly generate like this:
randomquestion = (int)(Math.random() * 5 );

Changing recursive method to iterative

i have recrusive function which works fine. The problem is it gives stackoverflow error when the number of lines are huge. I want to put it in iterative, probably using a for loop. Need some help in doing it.
private TreeSet validate(int curLine, TreeSet errorSet) {
int increment = 0;
int nextLine = 0;
if (curLine == lines.length || errorSet.size() != 0) {
return errorSet;
} else {
String line = lines[curLine];
//validation starts. After validation, line is incremented as per the requirements
increment = 1 //As per requirement. Depends on validation results of the line
if (increment > 0) {
try{
Thread.currentThread().sleep(100);
}catch(Exception ex){
System.out.println(ex);
}
nextLine = (curLine + increment);
validate(nextLine, errorSet);
}
}
return errorSet;
}
Poster's description of the method:
The method does validates textlines, these lines has instructions of how much line has to be skipped, if the line is valid. So, if the line is valid that many of lines will be skipped using the increment. if the line is not valid increment will be 0.
I'm not sure why this was ever recursive in the first place. This is perfectly suited for the use of a FOR loop. use something like so:
private TreeSet validate(int curLine, TreeSet errorSet) {
int increment = 0;
if (errorSet.size() != 0)
return errorSet;
for (int curLine = 0; curLine < lines.Length; curLine += increment)
{
// put your processing logic in here
// set the proper increment here.
}
}
If the increment is always going to be 1, then you can just use curr++ instead of curLine += increment
for(String line : lines) {
// validate line here
if(!errorSet.isEmpty()) {
break;
}
}
The solution for your problem could be simple for loop or while, with logical expression for stop condition. Typically we use for loop when we have to pass through all elements of Iterable or array. In case when we are not aware how many loops we are going to do we use a while loop. Advantage of for loop over while, is that we for free have localized variables so we ca not use them out side of the loop, therefore we reduce possibility to have some bug.
You problem is that you have to break the program on two conditions:
When errorSet is not empty.
When the array of lines have no longer items.
As contradiction, we can say that your program should continue:
Until errorSet is empty,
and until line number is smaller than array size where they are stored.
This provide us to simply expression
errorSet.isEmpty()
lineNumber < lines.length()
We can combine them using logical operator && and use as a stop rule in for loop.
for(int lineNumber= 0; errorSet.isEmpty() && lineNumber< lines.length(); lineNumber++) {
//code to operate
}
Note:
Typically for logical expression is used operator &&, that assure that every part of the logical expression is evaluated. An alternative for this is &, that in case of false do not operate longer and return false. We could be tempted to use this operator for this expression but i would be bad idea. Because when we would traversed all lines without error code will generate IndexOutOfBoundException, if we switch the places then we would not have any optimization as first expression would be evaluated same number of times.

Categories

Resources