Ok, so I can't figure out why when I input an array of 1, 2, 100, 3, 9, 22, 58
the following code returns 100:
(this is just a snippet, this is part of a larger block of code)
double result = numbers[0];
for (int i = 0; i < numbers.length; i++)
if (numbers[i] > result)
result = numbers[i];
System.out.println("The max value is " + result);
But without the curly brackets on the if, it prints a list of numbers leading to the biggest one, starting from the first one, in this case: 1 2 100:
double result = numbers[0];
for (int i = 0; i < numbers.length; i++)
if (numbers[i] > result) {
result = numbers[i];
System.out.println("The max value is " + result);
}
Thanks for your help in advance, this is driving me crazy and it's probably very stupid.
In the second example you are printing within the if statement, so each time it iterates through the list, it prints out a result. In the first example, it does it after the if because you don't use braces. When you don't you {} braces after a statement, it assumes only the very next line is included in that statement.
You should learn good coding practices before you continue to code. It will help you avoid things like this later on when your code is much more complex. Additionally, stepping through the code will show you exactly what is happening, so you should also learn how to use the debugger.
in
if (numbers[i] > result)
result = numbers[i];
System.out.println("The max value is " + result);
the if block without braces only includes the immediate next line.
same for the for block.
Explanation.
the for does not have braces, so it will just iterate through the immediate next block of code, which is the if block.
the if block has no braces either, so it will iterate through the immediate next block/statement which is
result = numbers[i];
so effectively your System.out.println("The max value is " + result); statement is out of both the blocks in the first case and hence executes only once.
In the first case, result is being set to the current number (number[i]), if that number is greater than the previous value of result. This has the effect of updating result to the largest value found so far, as long as it's larger than the first value its set to (numbers[0]). If you print this at the end of the loop, you're therefore printing the largest number found in the array (max value). In the second case, you are always printing the largest number found so far in the array, as you go through the numbers array - therefore you are printing the numbers in ascending order.
In the first example, the System.out.println is only executed once, at the end of the block. In the second example, it is executed every time a new highest-so-far number is encountered.
Adding braces to both examples should make the difference clear:
for (int i = 0; i < numbers.length; i++) {
if (numbers[i] > result) {
result = numbers[i];
}
}
System.out.println("The max value is " + result); // only ever called once
vs
for (int i = 0; i < numbers.length; i++) {
if (numbers[i] > result) {
result = numbers[i];
System.out.println("The max value is " + result); // called whenever numbers[i] > result
}
}
whenever you find a greater number than result you swap it with result and also print it out.
System.out.println("The max value is " + result);
should be right after the for loop (outside the curly braces) so when the loop will be over only the greatest number will be printed out.
double result = numbers[0];
for (int i = 0; i < numbers.length; i++)
{
if (numbers[i] > result) //this will check each array members to find the max
{
result = numbers[i];//assign the array member if it is the largest
}
System.out.println("The max value is " + result); //print the max value of the array
Read up on java and it's control flow statements.
If- and for-statements both have a clause - which is the code that is controlled. It can be a single statement or a group of statements wrapped with braces.
Read this:
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/flow.html
I'd review how to step through code with a debugger as BobbyD17 suggested.
For eclipse refer to this link.
For netbeans.
Related
class Example {
public static void main(String args[]) {
double nums[] = {10.1, 11.2, 12.3, 13.4, 14.5};
double result = 0;
int i;
for(i=0; i<5; i++)
result = result + nums[i];
System.out.println("Average is " + result / 5);
}
}
Sorry if the question is too stupid to ask, but I need to know. why do we have to declare double result = 0?
and why write result = result + nums[i]? why cant we write just result = nums [i]?
why do we have to declare double result = 0?
It's because your result variable is a block variable which means
you need to initialize it first before you can use it.
why write result = result + nums[i]? why cant we write just result = nums [i]?
result = nums[i] only assigns the value in the variable.
result = result + nums[i] assigns the sum value of result and nums[i].
You can also use this.
result += nums[i];
instead of this.
result = result + nums[i];
Writing result = nums [i] will assign the value of nums[i] to result, while writing result = result + nums[i] will assign the current value of result plus nums[i] to result.
So every time you go around your loop, you're adding the value of nums[i] to result, instead of replacing it.
Declaring result = 0 just initialises result to the value of 0.
Alright! Alright! Alright!, Here it is. A simple explanation -
Suppose You write result = num[i] inside the for-loop.
During the iteration inside for-loop, where you are writing System.out.println("Average is " + result / 5);
The consequent output will be -
For Iteration 1 - Average is 10.1/5
For Iteration 2 - Average is 11.1/5
For Iteration 3 - Average is 12.3/5
and So on.. for next two iterations.
As you can see, they are not adding up. Its just dividing the index value of your array and printing it.
So, to add the index values of your Array, You need result = result + nums[i]
Now, here is a twist. Since, you are writing result = result + nums[i], thus updating the result value. For first Iteration, there will no previous result value. No updation since previous Value is not known. Hence, you got yourself compilation error.
Consider the following code, which counts how many of each element an array has:
public static void getCounts(int[] list) {
int current = list[0];
int count = 0;
for (int i = 0; i < list.length; i++, count++) {
if (list[i] > current) {
System.out.println(current + " occurs " + count + timeOrTimes(count));
current = list[i];
count = 0;
}
}
System.out.println(current + " occurs " + count + timeOrTimes(count));
}
For this question, please assume list is sorted in ascending order. If list is [1, 1, 2, 3, 4, 4], for example, the output is:
1 occurs 2 times
2 occurs 1 time
3 occurs 1 time
4 occurs 2 times
Now, if I get rid of the println that comes after the for-loop, i.e.
public static void getCounts(int[] list) {
int current = list[0];
int count = 0;
for (int i = 0; i < list.length; i++, count++) {
if (list[i] > current) {
System.out.println(current + " occurs " + count + timeOrTimes(count));
current = list[i];
count = 0;
}
}
// System.out.println(current + " occurs " + count + timeOrTimes(count));
}
Then using the same example input, the output becomes:
1 occurs 2 times
2 occurs 1 time
3 occurs 1 time
In other words, the if block doesn't execute if list[i] is the maximum value of the array. Why is this the case? For the example above, the index of the first 4 is i = 4, and list[4] > 3, so the conditional statement is met, but it still won't execute.
How can I adjust the code so that the if block will run for all cases?
Thanks
The final println is necessary because you are triggering your print statement on a change in the value of list[i] and printing the result for the previous value. At the end of the program there's no last "change" to be detected, so you need to handle the last case separately.
This (the need for a final operation after the loop) is a standard coding pattern that occurs any time a variable change in a sequence triggers an operation at the end of a batch. One way of thinking about it is that there's a virtual value, one past the end of your array, that is always larger than any possible previous value and signals the end of data. There's no need to test for it or actually implement it, but you still have to code the operation (in your case a println).
The operation could be much more complex, in which case you'd encapsulate it in a method to avoid code duplication. Your code could benefit slightly from encapsulating the println in a method outputCount(int value, int count).
For example
private void outputCount(int value, int count) {
System.out.println(value + " occurs " + count + timeOrTimes(count));
}
For your use case it's almost not worth it, but if the end-of-batch operation were much more than 1 line of code I would certainly write a method for it instead of repeating the code.
I asked a question about my code the other day, which was quickly resolved by the incredible community here. However I have encountered a completely separate problem using a re-written version of my code. Here's a description of the program from my previous post.
I'm trying to write a program that can detect the largest sum that can be made with any subset of numbers in an ArrayList, and the sum must be lower than a user-input target number. My program is working flawlessly so far, with the exception of one line (no pun intended). Keep in mind that this code isn't complete yet too.
My problem with the code now is that after the user inputs a target number, the program outputs an infinite loop of 0's. Even after trying to debug, I still come up with problems. The ArrayList is being applied to the program perfectly fine, but I think I may have a problem somewhere within one of my while loops. Any ideas?
Heres the code.
import java.util.*;
class Sum{
public static void main(String[] args){
Scanner input = new Scanner(System.in);
int temp = 0, target = 1, result = 0, firstIndex = 0, secondIndex = 0;
String tempString = null;
ArrayList<String> list = new ArrayList<String>();
ArrayList<Integer> last = new ArrayList<Integer>();
System.out.println("Enter integers one at a time, pressing enter after each integer Type \"done\" when finished.\nOR just type \"done\" to use the default list.");
String placehold = "NotDone";
while (!placehold.equals("done")){
list.add(input.nextLine());
placehold = list.get(list.size() - 1);
}
list.remove(list.size() - 1);
if (list.size() == 0){ //Inserts default list if said list is empty
list.add("1");
list.add("2");
list.add("4");
list.add("5");
list.add("8");
list.add("12");
list.add("15");
list.add("21");
}
for (int i = 0; i < list.size(); i++){
tempString = list.get(i);
temp = Integer.parseInt(tempString); //Changes the items in the list to Integers, which can be inserted into another list and then sorted
last.add(temp);
}
Collections.sort(last);
System.out.println("Enter the target number");
target = input.nextInt();
while (result < target){
firstIndex = last.size() - 1;
secondIndex = firstIndex - 1;
while (last.get(firstIndex) > target){
firstIndex--;
}
if (last.get(firstIndex) + last.get(secondIndex) < result){
result = last.get(firstIndex) + last.get(secondIndex);
last.remove(firstIndex);
last.remove(secondIndex);
last.add(result);
}
else{
secondIndex--;
}
System.out.println(result);
}
}
}
And the Output...
Enter integers one at a time, pressing enter after each integer Type "done" when finished.
OR just type "done" to use the default list.
done //Prompting to use the default list
Enter the target number
15 //User inputs target number
0
0
0
0
0
0
... //And so on
target = input.nextInt();
should be within your loop otherwise the variable will never change and
while(result<target) will never turn to false
while(result<target) {
target = input.nextInt();
// otherCoolCode
}
You are assigning target before the while loop, and you are not altering target any way inside the while loop. You need to prompt the user within the while loop. Otherwise, if you set a target variable higher than 0, it will be an infinite loop.
The problem is in
if (last.get(firstIndex) + last.get(secondIndex) < result) {
...
}
Result is always initialized to zero, so that condition will never be true.
One possible fix is to add an extra condition to handle this initial case:
if (result == 0 || last.get(firstIndex) + last.get(secondIndex) < result) {
...
}
An infinite loop occurs when you have a loop whose condition(s) do not change during an iteration of the loop.
Let's review your loop:
while (result < target){
firstIndex = last.size() - 1;
secondIndex = firstIndex - 1;
while (last.get(firstIndex) > target){
firstIndex--;
}
if (last.get(firstIndex) + last.get(secondIndex) < result){
result = last.get(firstIndex) + last.get(secondIndex);
last.remove(firstIndex);
last.remove(secondIndex);
last.add(result);
}
else{
secondIndex--;
}
System.out.println(result);
}
Your loop will only end if result and/ortarget change so that result < target is false.
Within your loop you assign to result only when (last.get(firstIndex) + last.get(secondIndex) < result) is true. So if that condition is false then result will not change.
You have some additional state that is not in the loop condition itself but is manipulated by the loop: firstIndex and secondIndex. Every iteration of the loop you assign to them. You do have an 'else' clause where you modify secondIndex just before printing the current value of result, however you then immediately assign to it at the top of the loop.
This is the crux of your infinite loop (when last.get(firstIndex) + last.get(secondIndex) < result is false):
result doesn't change
Your list last isn't modified, thus last.size()-1 and firstIndex - 1 remain the same
You assign secondIndex = firstIndex - 1; overwriting the decrement at the end of the loop, thus neither firstIndex nor secondIndex change
In this line
if (last.get(firstIndex) + last.get(secondIndex) < result) {
the sum of both your values will hardly ever be less than result, which is "0".
I'm writing a program for a class at school, and when the independents couldn't help, I turn to you...
I encounter my issue when I attempt to find the average - the variables either don't add correctly or they don't divide correctly. For example, an input of [4], [2], [4], [2], will give me 7.0, when it should be 3.0. Similarly, [2], [2], [4], [4], will give 2.0.
As far as I'm aware, the rest of the code functions exactly as it should. I'm including only what should effect it, but I can post the rest if required.
public class ArrayFunctions
{
String elementNumber =
JOptionPane.showInputDialog("How many elements do you want?");
int number = Integer.parseInt(elementNumber);
//assigns how many elements are in the array, based on user input
int[] min_array = new int[number];
int recalculate = 0;
public void arrayValues()
{
for (int i = 1; i < (number + 1); i++)
{
String elementInfo =
JOptionPane.showInputDialog("Input value for element " + i);
int element = Integer.parseInt(elementInfo);
//assigns values for elements, based on user input
min_array[(i - 1)] = element;
}
System.out.println('\u000C'); /*using BlueJ, this clears the console*/
for (int i = 1; i < (number + 1); i++)
{
System.out.println(min_array[(i - 1)]);
}
//prints the values of the elements in the array
}
...
public double avg()
{
for (int i = 1; i < (min_array.length); i++)
{
recalculate = (recalculate + min_array[(i - 1)]);
}
//should add together the values of all the elements
//this may be where it stops working as intended
double array_avg = (recalculate / min_array.length);
return array_avg;
//should divide the sum of all the elements by how many elements there are
//this is the other place where it might stop working.
}
Again, I can post more code if required. Sorry about bad/lacking comments and poor structure at times, I need to get this written, because I've a due date for this. :/
for (int i = 1; i < (min_array.length); i++)
{
recalculate = (recalculate + min_array[(i - 1)]);
}
This loop is going between index 0 (1 - 1) and index min_array.length - 2 due to your boolean condition in the for loop, stating that it should go while i is LESS than the array's length, and then also subtracting it by 1 in the code.
A possible solution would be to simply go until it's less than OR equal to the size, or simply start your loop at 0 and stop the (i - 1) stuff in the average calculation.
for (int i = 0; i < min_array.length; i++)
{
recalculate += min_array[i];
}
Also, on a side note, you're basically making that same mistake in the GUI stuff as well above; I've corrected it (as well as kept your methodology of using 1-based indexing for asking the user to fill in values, rather than 0-based indexing)
for (int i = 0; i < number; i++){
String elementInfo =
JOptionPane.showInputDialog("Input value for element " + (i + 1));
int element = Integer.parseInt(elementInfo);
min_array[i] = element;
}
System.out.println('\u000C'); /*using BlueJ, this clears the console*/
for (int i = 0; i < number; i++){
System.out.println(min_array[i]);
}
I see that you're going from index 0 to index array.length - 2, instead of -1. That's the problem. I hope this helps
public double avg()
{
for (int i = 0; i < (min_array.length); i++)
{
recalculate = (recalculate + min_array[i]);
}
//should add together the values of all the elements
//this may be where it stops working as intended
double array_avg = (recalculate / min_array.length);
return array_avg;
//should divide the sum of all the elements by how many elements there are
//this is the other place where it might stop working.
}
Also always start a for loop with i=0 for counting purposes
I'm a student, trying to write a program that tests probability. It's called TestLuck it's supposed to generate a user determined amount of IntArrayLogs(ADT's) that are populated with random values. The program is supposed to calculate how many values were generated before there is a match to the first value.
Actual Problem:
"Create application TestLuck; have the user enter the upper limit of the random integer range (the book says 10,000, but you should also test with 365) as well as the number of times to run the test. Compute and output the average."
This is what I came up with, but I'm not getting the correct results for some reason, I tested the methods I use and they seem to work right, I think it's something to do with how I'm keeping track of the counter.
for(int k=0; k<numTests; k++) {
for(int i=0; i<upperLimit; i++) {
arrLog.insert(n);
n = rand.nextInt(upperLimit);
if(arrLog.contains(arrLog.getElement(0))) {
totalCount += i;
break;
}
if(i == upperLimit-1)
totalCount +=i;
}
System.out.println("Total Count: " + totalCount);
arrLog.clear();
}
testAverage = totalCount/numTests;
System.out.println("Average tests before match: " + testAverage);
Contains Method:
// Returns true if element is in this IntLog,
// otherwise returns false.
public boolean contains(int element) {
int location = 0;
int counter = 0;
while (location <= lastIndex) {
if (element == log[location]) { // if they match
counter++;
location++;
if(counter == 2)
return true;
} else
location++;
}
return false;
}
You don't need a contains() method, as this will only take more time to compute something as simple as a comparison.
The question is how many numbers have to be generated before matching the first number, but you need to take into account if this includes the first number. eg. {1,2,3,4,1} count = 5, or {1,2,3,4,1} count = 4. Either way, this wont affect the logic on this answer:
If you re-arrange your method it will work much faster.
for(int k=0; k<numTests; k++){
for(int i=0; i<upperLimit; i++){
arrLog.insert(n);
if(arrLog.getElement(0) == n && i != 0){// i != 0 to prevent it from counting a match on the first iteration
totalCount += i;//totalCount += i+1 if you are counting the first number
break;
}
n = rand.nextInt(upperLimit);
}
System.out.println("Total Count: " + totalCount);
arrLog.clear();
}
testAverage = totalCount/numTests;
System.out.println("Average tests before match: " + testAverage);
If you are required to use a contains() method let me know on the comments and I'll edit the answer.
I would also like to suggest not using any storage data structure, in this case an ADT's IntArrayLog (again, I dont know if you are required to use ADT as part of your course); so that your program will run even faster:
int firstNum;
for(int k=0; k<numTests; k++){
firstNum = rand.nextInt(upperLimit);
for(int i=1; i<upperLimit; i++){//notice this starts in 1
n = rand.nextInt(upperLimit);
if(firstNum == n){
totalCount += i;//totalCount += i+1 if you are counting the first number
break;
}
}
System.out.println("Total Count: " + totalCount);
arrLog.clear();
}
testAverage = totalCount/numTests;
System.out.println("Average tests before match: " + testAverage);
I find some odd things in your code.
First, you are inserting n to arrLog before giving n a value.
Second, you are testing if i == upperLimit-1 after the for loop to add 1 to the counter. You will only meet this condition if the for loop breaks in the last step (in which case you had added 2 to the counter).
Third, in the contains method you are returning true if you find element twice. As I understand the first time should be in position 0 (the first element) and then the test itself, yet you are passing the first element as argument. You should probably begin location in 1 (skipping first element) and count it once:
for (location=1; location<=lastIndex; location++) {
if (element = log[location]) return true;
}
return false;
However it should be easier just to compare n with arrLog.getElement(0)
P.S. I'm assuming everything else is properly initialized.