Is there a neater way to do this? Java IF - java

public void moveRowItemToBottomIfAllowed(int r, int f) {
int i = rows[r].peek().getType();
int j = 0;
if (bottom[f].isEmpty()) {
for (int k = 0; k < 4; k++) {
if ((k == f) || (bottom[k].isEmpty()) || (bottom[k].peek().getType() != i)) {
continue;
}
j = 1;
}
if (j == 0) {
bottom[f].push(rows[r].pop());
}
} else if ((!bottom[f].isEmpty()) && (rankTrueFalse(rows[r].peek(), bottom[f].peek())) && (rows[r].peek().getType() == bottom[f].peek().getType())) {
bottom[f].push(rows[r].pop());
}
}
As I'm still learning java I've been putting together some rules for a game, I went through how to do it logically and came up with the above code which works correctly but it looks like a bit of a mess - is there any neater way or a more efficient way of writing this code? any pointers are much appreciated.

I would extract methods to make the code more readable. At first sight I would extract
the for loop, or probably the whole contents of the if block,
the expression from the 2nd long else if
Use descriptive names for your new methods (and for your variables too, for that matter). This makes a huge difference in readability.

I would recommend that you use more descriptive names for your variables. What is r? What is f? I'm guessing that f is some sort of numeric representation of the suit, since you compare it to k, which iterates over four values.
There might be more to say about the code overall, but the first step is to write the code in a self documenting manner.

There are bits of expressions which could be extracted into local variables: rows[r].peek() and bottom[f].peek() being the most obvious ones.

It looks like you are using j as a flag. Booleans are better for that, but you can return early instead of setting the condition that guards the rest of the processing, getting rid of j entirely.
You're double checking that bottom[f].isEmpty()) is false, and can use the already looked up i instead of repeating rows[r].peek().getType()
Both sides of your first condition, if they end up doing the processing, do the same processing, which you can write once:
public void moveRowItemToBottomIfAllowed(int r, int f) {
int i = rows[r].peek().getType();
if (bottom[f].isEmpty()) {
for (int k = 0; k < 4; k++) {
if (k == f) continue;
if (bottom[k].isEmpty()) continue;
if (bottom[k].peek().getType() == i) return;
}
} else {
if (!rankTrueFalse(rows[r].peek(), bottom[f].peek())) return;
if (bottom[f].peek().getType() != i) return;
}
bottom[f].push(rows[r].pop());
}
This code is then structured as a bunch of guards with early exits, followed by the processing.
The guards could then be extracted into their own method, leaving:
public void moveRowItemToBottomIfAllowed(int r, int f) {
if (moveIsAllowed(r,f)) bottom[f].push(rows[r].pop());
}

Related

Given two lists V1 and V2 of sizes n and m respectively. Return the list of elements common to both the lists and return the list in sorted order

class Solution {
public static ArrayList<Integer> common_element(ArrayList<Integer>v1, ArrayList<Integer>v2) {
ArrayList<Integer> com = new ArrayList<>();
Collections.sort(v1);
Collections.sort(v2);
int i = 0;
int j = 0;
while (i < v1.size() && j < v2.size()) {
if (v1.get(i) == v2.get(j)) {
com.add(v1.get(i));
i++;
j++;
} else if (v1.get(i) > v2.get(j)) {
j++;
} else {
i++;
}
}
return com;
}
}
Question description:
Duplicates may be there in the output list.
What's wrong with my code. When I run it, it will easily and successfully be compiled but when I submit the code, it shows not working like the output coming from my code is wrong.
But where it fails, I'm not able to understand. Can anyone help me to know this....!
Your approach to find Common elements between given two Lists is perfectly fine. Can't figure out why you are not getting the correct verdict.
I'll suggest you to try the below modification and check if it works.
while (i < v1.size() && j < v2.size())
{
int x1 = v1.get(i), x2 = v2.get(j);
if (x2 == x1)
{
com.add(x1);
i++; j++;
}
else if (x1 > x2)
j++;
else
i++;
}
If the above works then it indicates that there might be some issue with the platform where you are submitting as the approach is exactly the same as yours.
If you are submitting it online, read the rule most of online competitions required your solution to have main method which read input from file or console and output in certain format. Other than that, your solution looks ok.

Cannot print out the right sum

I have assigned a letter grade to each student based on his/her grade. And I want to count the total number of students for each letter grade. But for some reasons, the result turns total wrong. Can anyone tell me what parts I did wrong? Thank you!
String letter ="A";
int letterA=0;
int letterB=0;
int letterC=0;
int letterD=0;
int letterF=0;
int a=0;
int b=0;
int c=0;
int d=0;
int f=0;
for (int row=0;row<100;row++){ //the outer loop, have 100 rows to go through
for ( int column=0;column<words.length;column++) {
if(words[column].equals(table[row][column])){ // compare two arrays
count++; }// add the score for each student if he/she is right
}
if (count >=18)
letter=("A");
if(count>=16 && count<18)
letter=("B");
if(count>=14 && count<16)
letter=("C");
if(count>=12 && count<14)
letter=("D");
if(count<12)
letter=("F");
System.out.println("Student Grade: "+letter+"\t");
count=0; // make sure the count will go back to 0, and run the loop again
if (letter.equals("A"))
letterA++;
a+=letterA;}
if (letter.equals("B"))
letterB++;
b+=letterB;
if (letter.equals("C"))
letterC++;
c+=letterC;
if (letter.equals("D"))
letterD++;
d+=letterD;
if (letter.equals("F"))
letterF++;
f+=letterF;
System.out.print("Question A "+a);
System.out.print("Question B "+b);
System.out.print("Question C "+c);
System.out.print("Question D "+d);
System.out.print("Question F "+f);
}
Always use braces, even for single statements:
if (letter.equals("A"))
letterA++;
a+=letterA;}
if (letter.equals("B"))
letterB++;
b+=letterB;
if (letter.equals("C"))
letterC++;
c+=letterC;
if (letter.equals("D"))
letterD++;
d+=letterD;
if (letter.equals("F"))
letterF++;
f+=letterF;
Should always be:
if ("A".equals(letter)) { letterA++; }
else if ("B".equals(letter)) { letterB++; }
else if ("C".equals(letter)) { letterC++; }
else if ("D".equals(letter)) { letterD++; }
else if ("F".equals(letter)) { letterF++; }
else { throw new RuntimeException("Invalid Letter " + letter); }
Use single line statements if you want them visually compact, but
still use the braces as they guarantee the intent of what is to be
done in a given block, they also act as documentation of that intent
for people in the future ( people includes you ) to know what is going
on.
I see no valid reason for the single letter variables they are never used and I do not understand why they are there?
General Critique:
Always use braces:
Leaving out braces means only the first statement after the if is executed when the if matches, the next line(s) are always executed.
if (letter.equals("A"))
letterA++;
a+=letterA;
is actually
if (letter.equals("A")) { letterA++; }
a+=letterA;
Which means that line outside the braces will always get executed no matter what the expression inside the if test evaluates to. The indention of the second line is conflating that statement as part of the if block and it is not.
There is absolutely nothing to gain by leaving out braces and
everything to lose.
Neat code is easy to read and maintain and shows you care:
Always format your code consistently and not so densely so you can tell what is going on and what was wrong with the braces missing version.
Look at the best advertising it has plenty of white space, clean formatted code should have plenty of consistent white space as well so that our brains can quickly pattern match and scan for relevant things like matching pairs of braces.
Clean formatted code is just a keystroke away in all IDEs worth using.
Clean code shows you care about what you are doing and makes your question more appealing, which means others will care about their answer just as much.
Clean code earns you respect from your peers that know what they are looking at and sets you apart from those that do not care or know what they are looking at.
Most Importantly Clean Code is easier to reason about and has less
bugs, no subtle bugs and is orders of magnitude easier to maintain.
Always cover all the conditions:
Always use if/else if/else with mutually exclusive tests.
If all the if clauses are mutually exclusive and you match the first one, all the rest are still evaluated for no reason with the if/if/if/if structure. if/else if/else if/else if/else only evaluates until something matches or nothing matches.
Without else you do not cover all possible cases that do not match, which is usually and error that will just occur silently without the else.
Do not just cover the happy path, cover the exceptional path, but do it in the least defensive manner possible.
Explicit is always better than Implicit!
Avoid == null checks; avoid null completely:
Always compare literals to variables with .equals() to avoid possible NullPointerExceptions.
Avoid using null references completely, it is possible in every case, even the cases that it seems like a legitimate reason.
If Tony Hoare, the inventor of them thinks it is a mistake
who is to argue.
Always Name your variables descriptively!
I am not sure what letterA is supposed to represent anymore than what a is supposed to represent. So no one can tell you if these are correct because no one knows for sure what they represent semantically.
No Unnamed Numerical Constants ( Magic Numbers ):
final int A_GRADE = 18;
final int B_GRADE = 16;
final int C_GRADE = 14;
final int D_GRADE = 12;
Given the way they are used the names arguably could be even better
like MINIMUM_A_GRADE, but that is opinion based, the lesson is avoid
magic numbers.
Do range checks in the same direction:
Do range checks in the same direction so that the variable is visually in the middle of the comparison.
This makes it harder to break the logic later on and is self documenting that it is a range check.
if (count >= A_GRADE) { /* omitted */ }
else if (B_GRADE <= count && count < A_GRADE) { /* omitted */ }
else if (C_GRADE <= count && count < B_GRADE) { /* omitted */ }
else if (D_GRADE <= count && count < C_GRADE) { /* omitted */ }
else /* isF */ { /* omitted */ }
Which one is easier to reason about and maintain?
Do not hesitate to have many small methods if they make the code more self documenting:
private static boolean isA(final int count) { return count >= A_GRADE; }
private static boolean isB(final int count) { return B_GRADE <= count && count < A_GRADE; }
private static boolean isC(final int count) { return C_GRADE <= count && count < B_GRADE; }
private static boolean isD(final int count) { return D_GRADE <= count && count < C_GRADE; }
then you will have the following:
if (isA(count)) { /* omitted */ }
else if (isB(count)) { /* omitted */ }
else if (isC(count)) { /* omitted */ }
else if (isD(count)) { /* omitted */ }
else /* isF */ { /* omitted */ }
Which one is more obvious and self documenting, thus more
maintainable?
DRY - Don't Repeat Yourself:
Logically if (count >= A_GRADE) { letter = "A";} is exactly the same as if ("A".equals(letter)) { /* do stuff */ } so this is duplicated logic.
Instead of assigning a letter than checking that again, just put the logic in the original check.
if (count >= A_GRADE) { /* do stuff */ }
else if (B_GRADE <= count && count < A_GRADE) { /* do stuff */ }
else if (C_GRADE <= count && count < B_GRADE) { /* do stuff */ }
else if (D_GRADE <= count && count < C_GRADE) { /* do stuff */ }
else { /* omitted */ }
I see no valid reason for the single letter variables they are never used and I do not understand why they are there?
Duplicate logic means multiple places to have errors and multiple
places to edit to fix bugs, save yourself time and effort and follow
the DRY principle.
Move large logic blocks to method calls:
When do stuff is more than a few lines, refactor it to a method call.
if (count >= A_GRADE) { recordMarkA(); }
else if (B_GRADE <= count && count < A_GRADE) { recordMarkB(); }
else if (C_GRADE <= count && count < B_GRADE) { recordMarkC(); }
else if (D_GRADE <= count && count < C_GRADE) { recordMarkD(); }
else { recordMarkF(); }
More small methods with descriptive names is always better than large
monolithic blocks of inline code.
This question shows substantial effort and a genuine desire to learn:
So I crafted up what I would want a complete solution ( provided the partial/incomplete code ) to look like.
Q34081279.java
public class Q34081279
{
final static int A_GRADE = 18;
final static int B_GRADE = 16;
final static int C_GRADE = 14;
final static int D_GRADE = 12;
public static void main(final String[] args)
{
final String[] words = new String[]{}; /* this is just a placeholer, not provided in question */
final String[][] table = new String[][]{}; /* this is just a placehoder, not provided in question */
int markA = 0;
int markB = 0;
int markC = 0;
int markD = 0;
int markF = 0;
for (int row = 0; row < 100; row++)
{
int count = 0;
for (int column = 0; column < words.length; column++)
{
if (words[column].equals(table[row][column])) { count++; }
}
if (count >= A_GRADE) { System.out.format("%d = A", count); }
else if (B_GRADE <= count && count < A_GRADE) { System.out.format("%d = B", count); }
else if (C_GRADE <= count && count < B_GRADE) { System.out.format("%d = C", count); }
else if (D_GRADE <= count && count < C_GRADE) { System.out.format("%d = D", count); }
else { System.out.format("%d = F", count); }
System.out.println();
}
System.out.println(String.format("Question A %d", markA));
System.out.println(String.format("Question B %d", markB));
System.out.println(String.format("Question C %d", markC));
System.out.println(String.format("Question D %d", markD));
System.out.println(String.format("Question F %d", markF));
}
}
#Buddy is on the right rack but it's more than that. All of the if statements with more than one line need to have braces.
Otherwise only the first line is read by the compiler. According to Oracle:
Deciding when to omit the braces is a matter of personal taste. Omitting them can make the code more brittle. If a second statement is later added to the "then" clause, a common mistake would be forgetting to add the newly required braces. The compiler cannot catch this sort of error; you'll just get the wrong results.
eg:
if (letter.equals("A")) {
letterA++;
a+=letterA;
}
if (letter.equals("B")) {
letterB++;
b+=letterB;
}

How to re-write or modify this code to work the same but without using a break statement

How can I get the following code work without using break statement?
I updated and added i = child to bottom of the while loop. I'm also adding these additional comments because someone edited my post and now I can't update it because I need to add more comments. Please don't alter my question. Those comments are there for extra insight. It also hinders my ability to edit my question or update my code.
private void percDown(int [] a, int i, int n) {
numOfCalls++;
int child = 0;
int tmp = a[i];
while(leftChild(i) < n) {
child = leftChild(i);
if( child != n - 1 && a[child] < a[child + 1]){
numOfComparisons++;
child++;
}
if( tmp < a[child]){
numOfComparisons++;
a[i] = a[child];
}
else
break;
i= child;
a[i] = tmp;
}
}
Just set n = 0; instead, or Integer.MIN_VALUE if these values can go negative. That will stop your loop. But don't be averse to break statements. They are used all the time out here in the real world.
Try this while condition:
while(leftChild(i) < n && (( leftChild(i) != n - 1 && a[leftChild(i)] < a[leftChild(i) + 1]) || tmp < a[leftChild(i)]))
Basically I have clubbed both your if conditions in the while condition. Everything else remains the same.
Your code is in structure like this:
while(A) {
B;
if(C){
D;
} else {
break;
}
E;
}
To tidy it up a bit; it can be written as
while(A) {
B;
if(C){
D;
E;
} else {
break;
}
}
To avoid using break, it can be done by:
while(A && !C) {
B;
if(C){
D;
E;
}
}
(You may make up a meaningful boolean flag to represent C so that it is more readable instead of putting a long, complex, hard-to-read predicate in while condition.)

How do I make a boolean method using a string?

This is what I have so far, I managed to reach here with several hours of work. The problem with my code is that if i give it a string "abcefg" it will verify the first two characters and returns it as true. I want the code to do it for all of my characters. I thought that putting the limit as x.length() would do the thing, but for some reason, it won't work.
public static boolean ConsecutiveCheckerAscending(String x) {
x = x.toLowerCase();
for (int i = 0; i < x.length() - 1; i++) {
if ((int)x.charAt(i) + 1 != ((int)x.charAt(i + 1)))
{
return false;
}
}
return true;
}
public static boolean ConsecutiveCheckerDescending(String x) {
x = x.toLowerCase();
for (int i = 0; i < x.length() - 1; i++) {
if((int)x.charAt(i) - 1 != ((int)x.charAt(i + 1)))
{
return false;
}
}
return true;
}
You have a variety of issues here.
Firstly, you can eventually go out of bounds with the charAt(i + 1) calls (check your loop condition).
Secondly, how can you possibly return true in the body of the for-loop? You haven't checked all of the characters yet!
I think you're making this overly complicated, though. All you need to do in order to check that two contiguous (i.e. next to each other in the string) characters are consecutive is
Math.abs(s.charAt(i) - s.charAt(i + 1)) == 1
You actually don't even need a cast. What we're doing is checking that the "distance" between the two characters is 1.
Just apply that to every contiguous pair of characters in the string, and return false if it isn't satisfied somewhere along the line. If you exit the loop without ever returning false, you can return true.
You cannot know for sure if the string is consecutive until the end of the method, so you cannot return true in the middle. At most you can return false when you find that string is not consecutive.
To give more advice, what do you mean by "consecutive"? Is adgkm consecutive? Looking at the current code it would look like it; all you check is the order of the characters. Is abcdcbcd consecutive? Usually "consecutive" means there are no gaps.
In both if and else statements you having return statement, So the method will return after first check. You have to give return only for the exit condition. don't give for both if and else
Wrote it in a rush, but it'd look something like this.-
public static boolean ConsecutiveChecker(String x) {
boolean consecutive = true;
x = x.toLowerCase();
for (int i = 0; i < x.length() - 1; i ++) {
if ((int) x.charAt(i) + 1 != ((int) x.charAt(i + 1))) {
consecutive = false;
break;
}
}
return consecutive;
}

Slow recursive function. How can I speed it up?

Below is a recursive function that does nothing. The real function does some checks that actually can remove some of the recursive calls but it's just an example to simplify the question.
public void speedtest2(char[] s) {
int a, c;
int l, lmax;
int arrlength = Array.getLength(s);
for (a = 0; a < arrlength; a++) {
if ((a == 0) || (s[a]) != s[a - 1]) {
if (s[a] == '*') {
lmax = 26;
} else {
lmax = 1;
};
for (l = 1; l <= lmax; l++) {
tot++;
char[] tmp = new char[arrlength - 1];
int p = 0;
for (c = 0; c < arrlength; c++) {
if (c != a) {
tmp[p++] = s[c];
};
};
speedtest2(tmp);
}
}
}
}
Calling speedtest with an array containing "srrieca*" will take up to 5 seconds on my lowly HTC Flyer android tablet. Granted in this extreme example, the function is called 1 274 928 times but still.
I'm pretty sure there is something to do to improve the speed of this example.
You can reduce the garbage collector overhead by pooling the tmp array. Of course after you have checked that this is a bottleneck in your case.
One possibility involves reducing the number of recursive calls by having some sort of cache that stores results that can be re-used, instead of recursing. Although in your contrived example, it's not clear what that would be.
Memory allocation is an expensive operation. Your speed is brought down by that new statement. Try to allocate one large block for a working area and stay within that.
Also you're going to trigger the garbage collector quite often, which is an even bigger speed bump.

Categories

Resources