Variable cannot be resolved in an If-Statement - java

I'm trying to do the below tutorial question.
// Create a method called greatestCommonFactor
// It should return the greatest common factor
// between two numbers.
//
// Examples of greatestCommonFactor:
// greatestCommonFactor(6, 4) // returns 2
// greatestCommonFactor(7, 9) // returns 1
// greatestCommonFactor(20, 30) // returns 10
//
// Hint: start a counter from 1 and try to divide both
// numbers by the counter. If the remainder of both divisions
// is 0, then the counter is a common factor. Continue incrementing
// the counter to find the greatest common factor. Use a while loop
// to increment the counter.
And my code is below
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Ex4_GreatestCommonFactor {
// This is the main method that is executed as
// soon as the program starts.
public static void main(String[] args) {
// Call the greatestCommonFactor method a few times and print the results
}
public static int greatestCommonFactor(int a, int b){
int i = 1 ;
while (i >= 1 ){
i++;
}
if (a%i == 0 && b%i == 0){
ArrayList factor = new ArrayList<Integer>();
factor.add(i);
}
else if (a%i <= 1 || b%i <= 1){
Collections.sort(factor);
List<Integer> topnum = factor.subList(factor.size() - 1, factor.size());
}
return topnum;
}
}
So I have 2 questions.
1) In my elseif statement, I get an error where factor cannot be resolved to a variable. How do I "carry over" the factor ArrayList from the previous If statement into this elseif statement?
2) I also get a similar error where topnum cannot be resolved. Is this also a placement error for this line of code in my method, or am I making a completely different mistake?

1) In my elseif statement, I get an error where factor cannot be resolved to a variable. How do I "carry over" the factor ArrayList from the previous If statement into this elseif statement?
by declaring it before if
ArrayList factor = null;
if ( /* some condition */ ) {
// initialize factor
} else if (/* some condition */) {
// access factor here
}

Each variable (amongst other 'parts' of java) has a scope, in which it is available.
The scope is usually the block in which the variable is declared.
Block: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/expressions.html
In your method greatestCommonFactor there are three variables, which are valid in the whole method:
a, b, i
You can access them everywhere from the start of you method (the first open brace) till the end of it (the last close brace).
The block inside your first if statement is an new scope. factor is declared in this scope and is no longer available, after program execution leaves this block.
if (a%i == 0 && b%i == 0){ // Start of Block/Scope
ArrayList factor = new ArrayList<Integer>(); // Declaration, you can access factor now
factor.add(i);
} // End of Block/Scope, factor inaccessible
The else if part is an new block with it's own scope.
else if (a%i <= 1 || b%i <= 1){
Collections.sort(factor);
List<Integer> topnum = factor.subList(factor.size() - 1, factor.size());
}
factor, being declared in the first block does not exists any more.
You could pull up the declaration and put it outside the if.
public static int greatestCommonFactor(int a, int b){
int i = 1 ;
while (i >= 1 ){
i++;
}
ArrayList<Integer> factor = new ArrayList<Integer>();
if (a%i == 0 && b%i == 0){
factor.add(i);
}
else if (a%i <= 1 || b%i <= 1){
Collections.sort(factor);
List<Integer> topnum = factor.subList(factor.size() - 1, factor.size());
}
return topnum;
}

Related

(Java) if statement not evaluating equality between int values

int count = charFreq.get(guessChar);
int matchedChars = updatedCharFreq.get('_');
if (updatedKeyVals.contains('_')) {
if (count == matchedChars) {
;
}
if (count < matchedChars) {
;
}
else {
count = count - matchedChars;
}
Method works if count < matchedChars, and also the else statement. It just skips past the if equality statement. I have been trying to figure it out, but just can't seem to.
As commented, you neglected to chain the first if with an else.
I suggest accounting for all cases explicitly plus an extra final case that should never be reached. The extra check is for defensive programming, to guard against editing errors.
if (count == matchedChars) {
// No code needed here.
} else if (count < matchedChars) {
// No code needed here.
} else if (count > matchedChars) {
count = count - matchedChars;
} else {
throw new IllegalStateException( … ) ; // Should never reach this point.
}
It seems you only care about the case where the first number is bigger than the second. So we could shorten this code.
if (count > matchedChars) {
count = count - matchedChars;
}
Alternatively, you can use the static method Integer.compare. To quote the Javadoc:
Returns: the value 0 if x == y; a value less than 0 if x < y; and a value greater than 0 if x > y
if( Integer.compare( count , matchedChars ) > 0 ) {
count = count - matchedChars;
}

Any comparasion condition returns bad value

I struggle with very strange behaviour while trying to compare two ints but first things first. Here is my method inside the class:
public class CollectionsTutorial {
private Collection<String> collection = null;
public CollectionsTutorial() {
this.collection = new ArrayList<String>();
for(int i=0;i<100000;i++) {
collection.add("item_"+((i+1)%10000));
}
}
public Set<String> getSet(){
HashSet<String> set = new HashSet<String>(10000);
for(String item: this.collection) {
if (!set.contains(item)) {
set.add(item);
}
}
return set;
}
public TreeSet<String> getEvery3ElementAsSortedSet(){
TreeSet<String> tree = new TreeSet<String>();
int counter = 0;
for(String item : this.collection) {
if (counter%2==0) {
tree.add(item);
counter = -1;
}
counter++;
}
return tree;
}
}
The whole class doesn't really matter here - it only holds ArrayList<String>. I need to return every 3rd element in a tree and everything goes well until it's time to compare current counter value. It returns true everytime. I'm sure of it becouse while testing it's adding to the Tree every single element of collection. I've tried using compareTo(), equalsTo(), valueOf() and intValue() but nothing helps.
EDIT.
I've change code to the class view - maybe something else is cousing the error?
Here is test i'm trying to pass
public class CollectionsTutorialTest {
#Test
public void GetEvery3ElementTest() {
CollectionsTutorial testObj = new CollectionsTutorial();
TreeSet<String> tree = new TreeSet<String>();
tree.addAll(testObj.getSet() );
assertEquals(false, tree.contains("item_2"));
}
}
"I need to return every 3rd element in a tree..." this description screams for the modulo % operator.
If you want to enter an if-condition on every 3rd iteration then you can check this with the following condition: counter % 3 == 0. You don't need to subtract anything at all.
How does % work?
Put simply: The modulo operator returns the result of a division.
Example:
5 / 3 = 1 with remain 2
5 % 3 = 2
9 / 3 = 3 with remain 0
9 % 3 = 0
Note:
if (counter % 2 == 0) {
tree.add(item);
counter = -1;
}
counter++;
You use counter % 2 == 0. This will return true for the second element. Afterwards you set counter = -1 because you intend to get every 3rd element. However, this does not work.
Here's the reason why:
System.out.println(0 % 1); // 0 % 1 = 0
System.out.println(0 % 2); // 0 % 2 = 0
System.out.println(0 % 3); // 0 % 3 = 0
System.out.println(0 % 4); // 0 % 4 = 0
As you can see, every time your counter reaches the value 0 the if-condition will result in true regardless of the divisor. That's why you use % 3.
the list is created by:
for(int i=0;i<100_000;i++) {
collection.add("item_"+((i+1)%10_000));
}
resulting in:
collection[0] = item_1
collection[1] = item_2
collection[2] = item_3
collection[3] = item_4
...
collection[9_998] = item_9999
collection[9_999] = item_0 // (9_999+1) % 10_000 is 0
collection[10_000] = item_1 // (10_000+1) % 10_000 is 1
collection[10_001] = item_2
collection[10_002] = item_3
collection[10_003] = item_4
...
collection[19_998] = item_9999 // (19_998+1) % 10_000 is 9_999
collection[19_999] = item_0 // (19_999+1) % 10_000 is 0
collection[20_000] = item_1
collection[20_001] = item_2
collection[20_002] = item_3
collection[20_003] = item_4
...
above is NOT code
now note that 20_001 % 3 is 0 - so the third item_2 will be picked; same true for 50_001 % 3 and 80_001 % 3. So, actually that item is added 3 times to the tree (since it is a Set, only one instance is kept). At the end, one version of each item will be present in the result. Similar to counter%3 == 1 or counter%3 == 2 (basically the first code version posted in question.)
Lesson: checking that item_2 is present or not, does NOT check if the condition "returns true everytime".
Better test:
...
int index = 0; // DEBUG
for(String item : this.collection) {
if (counter%2==0) {
System.out.println(index); // DEBUG
tree.add(item);
counter = -1;
}
index += 1; // DEBUG
...
above is not the full code, just showing idea for testing
Bonus:
a Set does not save duplicates ("A collection that contains no duplicate elements"), in below snippet:
if (!set.contains(item)) {
set.add(item);
}
the if is not necessary - this is already checked by add()

Return statement does not correctly terminate a recursive method

I have a method getNextPrime(int num) which is supposed to identify the closest prime number after the value received by the method.
If num is even, it will increment it and call itself again. If it is odd, it will run a for loop to check if it is divisible by odd numbers between 3 and num's half value. If it is then it will increase num by 2 and the method will call itself again, otherwise it will return the new num value which is a prime number.
The problem is, when the program gets to the return statement, it will jump to the if statement and return the original value of num + 1. I have been debugging this for a while and it just doesn't make sense. Wherever I place the return statement, the method just jumps to the if statement instead of terminating the method and returning the value to where it is being called from.
public int getNextPrime(int num){
if(num % 2 == 0){
//even numbers are not prime
getNextPrime(++num);
}
else{
for(int i = 3; i < (num + 1) / 2; i += 2){
if(num % i == 0) {
getNextPrime(num += 2); //consider odd numbers only
}
}
}
return num; //jumps to if and terminates
}
However, if I change the else statement to a separate if statement, if(num % 2 != 0) it works.
Why does this happen?
*Note - the values given to the method are greater than 3, the fact that 1, 2, and 3 are primes doesn't matter.
There is only one structural problem here. Reaching a single return does not collapse the entire call stack, it only returns to the previous invocation.
You need to save the result of calling getNextPrime() every time and use that as the return value, so the value actually found gets passed back along the call chain and returned to the initial caller. As it stands you return only the number that was passed in since you never modify it.
The fix is a very simple modification. Where you have
getNextPrime(++num);
... and ...
getNextPrime(num+2);
replace them with
return getNextPrime(++num);
... and ...
return getNextPrime(num+2);
The problem with the algorithm you chose is that it is inefficient. You need to test divisibility using smaller primes only, not all odd numbers, and only up to the square root of the original number.
Implementation is left as an exercise.
Lets try to look at the call stack when we call your function with argument 8;
The first call is : getNextPrime(8). As the number is even, the function goes into the if part and calls itself again with getNextPrime(9). This time the else part kicks in, checks for divisibility in for loop, finds that 9 is divisible so calls the getNextPrime(11). Now getNextPrime(11) goes again the else and the for loop and finds that 11 was prime and returns the number 11 to the caller, but if you look closely, you don't store this value in a variable, the num variable in the getNextPrime call was 9, and when getNextPrime(9) returns it returns that value to getNextPrime(8). In your getNextPrime(8) too you haven't really stored the num variable returned from the recursion call stack. You are just return the num variable defined in that function, which you happened to increment before calling the getNextPrime(11) so this value is 9, and 9 is returned.
Corrected program with the same if else block is given below for your reference.
public static int genNextPrime(int num) {
if (num % 2 == 0) {
num = genNextPrime(++num);
} else {
for (int i = 3; i < (num + 1) / 2; i += 2) {
if (num % i == 0) {
num += 2;
num = genNextPrime(num);
}
}
}
return num;
}
Your return statement works fine but ..you have left 1,2 and 3 out of your logic. 2 is a even prime number and 1 is not a prime number.

I think my code is correct but I keep getting zero?

Output that I want: 10 20 30 40 50..............
Output that I get: 0
public class HelloWorld
{
public static void main(String[] args)
{
final int n = 50;
int i= 0;
while(i <= n && i % 10 == 0 )
{
System.out.println(i);
i++;
}
}
}
while(i <= n && i % 10 == 0 )
This is the continuation condition which is two expressions connected by logical-and &&.
That means both must be true for the whole thing to be true.
Now work out the two sub-expressions for when i becomes 1. The first will be true but not so the second (1 is not a multiple of 10), meaning the loop will exit at that point. That explains why you're only seeing 0.
To fix it, you need to separate the two sub-expressions since the loop control depends only on the first. However, you still only want printing to happen for multiples of ten (the second).
So, assuming as per your desired output 10 20 30 40 50, you don't want 0 as one of the outputs (despite it being, after all, a multiple of 10), the following pseudo-code will do the trick:
set n to 50, i to 1
while i is less than or equal to n:
if the remainder when i is divided by 10 is 0:
output i
increment i
If you do want 0 included in the output, simply set i to 0 initially, and you'll see 0 10 20 30 40 50.
I've left the code above as pseudo-code on the assumption this is classwork of some description - it should be relatively easy to turn that into any procedural language.
i % 10 == 0
This will evaluate to false on the second loop so the while wont continue. I think you want this...
final int n = 50;
int i= 0;
while(i <= n)
{
if (i % 10 == 0) {
System.out.println(i);
}
i++;
}
This allows i to increment all the way up to n, but it will only print results when i % 10 == 0
You are trying to use the while and both a while and an if. Try
public class HelloWorld {
public static void main(String[] args) {
final int n = 50;
int i = 0;
while (i <= n) {
if (i % 10 == 0) {
System.out.println(i);
}
i++;
}
}
}
Loop run for once only for i=0. That's it.

Java For Loop conditional test

I'm sure this is a very basic question but having trouble understanding why the below FOR loop works?
The code below brings back a set number of Primes and works as it should. I understand the whole math reasoning behind using square root, however my issue is more with the conditional part of the FOR statement.
The first argument that is fed into isPrime() to check is 2 which of course is Prime. The first isPrime() gets the square root of 2 which is ~ 1.4.
At this point, I get confused. Starting at i = 2 which is obviously > 1.4 so than the starting condition of i <= root (ie 2 <= 1.4) has NOT been met. The IF statement should not run and it should return no result, but it does.
It doesn't seem to me like I should get any result back until I get to 5 because 2 is also > than the square root of 3. I'm obviously not understating either the initialization or conditional aspect of the FOR statement here? Can someone please help me with the logic?
class BooleanTest{
public static void main(String[] arguments) {
int quantity = 10;
int numPrimes = 0;
int candidate = 2; //starting prime #
System.out.println("First " + quantity + " primes:");
while (numPrimes < quantity) {
if (isPrime(candidate)) { //if isPrime Method true
System.out.println(candidate);
numPrimes++;
}
candidate++;
}
}
public static boolean isPrime(int checkNumber) {
double root = Math.sqrt(checkNumber); //get square root of candidate
for (int i = 2; i <= root; i++) {
if (checkNumber % i == 0) { //if remainder of candidate/i = 0
return false; //because candidate is not prime. has factor other than 1 and self.
}
return true;
}
}
For inputs 1, 2, 3 the loop will not execute at all, indeed. As a result, the return false statement in the body of the loop will not be executed as well. Instead the return true statement right after the loop will get executed and the result of the method call will be true for these inputs.
The first number for which the loop will execute is 4 and the method will correctly return false as 4 is divideable by 2.
Fixing the indentation of the code makes this behavior a bit easier to see:
public static boolean isPrime(int checkNumber) {
double root = Math.sqrt(checkNumber); //get square root of candidate
for (int i = 2; i <= root; i++) {
if (checkNumber % i == 0) { //if remainder of candidate/i = 0
return false; //because candidate is not prime. has factor other than 1 and self.
}
}
return true;
}
root is not initialized to sqrt(2), it's initialized to sqrt(checkNumber), which would be larger than 2 for most inputs. Therefore your So than the starting condition of i <= root (ie 2 <= 1.4) has NOT been met so then the IF statement should not run and I would get no result back assumption is false.

Categories