Implementing a infix to postfix calculator and need to check if an operator has a lower precedence than another. Here's what I have so far:
public enum Operators {
ADD('+', 2), SUBTRACT('-', 2), MULTIPLY('*', 4), DIVIDE('/', 4);
private char operator;
private int precedence;
Operators(char operator, int precedence) {
this.operator = operator;
this.precedence = precedence;
}
public char getOperator() {
return operator;
}
public int getPrecedence() {
return precedence;
}
}
private static boolean isOperator(char c) {
return c == Operators.ADD.getOperator() || c == Operators.SUBTRACT.getOperator()
|| c == Operators.MULTIPLY.getOperator() || c == Operators.DIVIDE.getOperator();
}
private static boolean isLowerPrecedence(char ch1, char ch2) {
// STUCK HERE
}
I've tried a number of different things to check the precedence of the char that is passed in but to no avail. Is there an easy way to compare two values of an enum? Will I have to create a loop?
It's easy to compare if you have a method that translates a "operator" char to an enum value.
For example:
static Operators getOperatorForChar(char op) {
for(Operators val: values())
if(op == val.operator)
return val; //return enum type
return null;
}
And then you can implement your method using:
private static boolean isLowerPrecedence(char ch1, char ch2) {
//assuming intention is to compare precedence of ch1 to that of ch2
return getOperatorForChar(ch1).precedence < getOperatorForChar(ch2).precedence;
}
You can loop the values of enum to match the right operator and compare its precedences:
private static boolean isLowerPrecedence(char ch1, char ch2) {
Integer first = null;
Integer second = null;
for (Operators o: Operators.values()) {
if (o.getOperator() == ch1) {
first = o.getPrecedence();
}
if (o.getOperator() == ch2) {
second = o.getPrecedence();
}
}
return (first != null && second !=null && first < second);
}
Returning boolean when the operator has not been found might be confusing. I recommend you to throw an exception in such case instead.
...
if (first == null || second ==null) throw new Exception("Operator not found.");
return first < second;
Or, you can compare the precedence like this:
private static boolean isLowerPrecedence(Operators operatorFirst, Operators operatorSecond) {
if(operatorFirst.getPrecedence() < operatorSecond.getPrecedence()){
return true;
} else {
return false;
}
}
Of course, it can be written as:
return operatorFirst.getPrecedence() < operatorSecond.getPrecedence();
By taking a look at this question, you can find out Java handles types comparisons via the Comparable and Comparator interfaces.
Of course, they are meant for more complex situations that this one, but I think you should take them into account so that you can see the proper way to deal with the set of ordering algorithms provided by the standard Java library.
Since you can't override default Enum's compareTo (it is declared as final), you can implement your own Comparator as such:
public class OperatorsComparator implements Comparator<Operators> {
#Override
public int compare(Operators o1, Operators o2) {
return o1.getPrecedence() - o2.getPrecedence();
}
}
Then you're going to need some kind of way to find the right Operators value from the char you give in:
private static Operators findOperator(char c){
for(Operators op : Operators.values()){
if(op.getOperator() == c)
return op;
}
return null;
}
By using a substraction between the two precedences and the previous Operators finder, you can implement your isLowerPrecedence method like this:
public static boolean isLowerPrecedence(char c1, char c2) throws Exception {
Operators o1 = findOperator(c1);
Operators o2 = findOperator(c2);
if(o1 == null || o2 == null)
throw new Exception("Invalid operators");
return new OperatorsComparator().compare(o1, o2) <= 0;
}
By comparing precedences this way, you'll get that o1 will be marked as lower precedence even if it has the same precedence as o2, as default behaviour.
Beware of the characters you try to use as operator, since you'll need to catch the Exception if anything goes wrong
Execution example:
System.out.println(isLowerPrecedence('+', '-'));
System.out.println(isLowerPrecedence('+', '*'));
System.out.println(isLowerPrecedence('/', '-'));
System.out.println(isLowerPrecedence('/', '*'));
System.out.println(isLowerPrecedence('*', '-'));
prints these messages:
true
true
false
true
false
You can use EnumLookup helper class proposed in this answer of mine (source code of EnumLookup there).
Upon redesining your Operators enum a little (I strongly suggest using a singular class name), you get:
public enum Operator {
ADD('+', 2), SUBTRACT('-', 2), MULTIPLY('*', 4), DIVIDE('/', 4);
private static final EnumLookup<Operator, Character> BY_OPERATOR_CHAR
= EnumLookup.of(Operator.class, Operator::getOperatorChar, "operator char");
private final char operatorChar;
private final int precedence;
Operator(char operatorChar, int precedence) {
this.operatorChar = operatorChar;
this.precedence = precedence;
}
public char getOperatorChar() {
return operatorChar;
}
public int getPrecedence() {
return precedence;
}
public static EnumLookup<Operator, Character> byOperatorChar() {
return BY_OPERATOR_CHAR;
}
}
private static boolean isOperator(char c) {
return Operator.byOperatorChar().contains(c);
}
private static boolean isLowerPrecedence(char ch1, char ch2) {
return Operator.byOperatorChar().get(ch1).getPrecedence() < Operator.byOperatorChar().get(ch2).getPrecedence();
}
The main drawback of this approach is that your char gets boxed into Character, but unless performance is critical for your application, I wouldn't worry about that (readability should be more important).
Related
Im trying to detect whether the last character of a string contains an operator using an array checker that was previously used for integers. For some reason the code will always display "Not In" Even if the last character is an operator
class Main {
public static boolean useLoopString(String[] arr, String targetValue)
{
for (String s : arr) {
if (s == targetValue)
return true;
}
return false;
}
public static void main(String[] args) {
String[] op={"+","-","×","÷"};
String eq = "43+4+";
String eqLast=eq.substring(eq.length()-1);
System.out.println(eqLast);
boolean in=useLoopString(op,eqLast);
if(in){
System.out.println("In");
}
else{
System.out.println("Not In");
}
}
}
You can use char to compare, like this:
public static boolean useLoopString(char[] arr, char targetValue) {
for (char ch : arr) {
if (ch == targetValue)
return true;
}
return false;
}
public static void main(String[] args) {
char[] op = { '+', '-', '×', '÷' };
String eq = "43+4+";
char eqLast = eq.charAt(eq.length() - 1);
boolean in = useLoopString(op, eqLast);
if (in) {
System.out.println("In");
} else {
System.out.println("Not In");
}
}
Using == on class objects checks whether the two objects are the exact same instance, rather than whether the objects are equivalent, as you are intending. Instead, you should use .equals as Strings are classes:
public static boolean useLoopString(String[] arr, String targetValue) {
for (String s : arr) {
if (s.equals(targetValue))
return true;
}
return false;
}
String equality should be checked using the equals method. One should not use the object reference comparison.
In your case s and targetValue might be logically equal but may or may not point to the same String object.
Therefore, replace
if (s == targetValue)
with
if (s.equals(targetValue))
Also, null check should be made before making method calls on any object.
typically in production world, Edge cases if array has null element, you end up with null pointer exception.
always safe to use if(s!=null && s.equals(targetValue))
or
use apache's StringUtils.equals(String a, Strin b)
I've already read many previous questions here and elsewhere, but I haven't found what I need.
I need to write a recursive implementation of indexOf. The problem is that I can't use any local variables and have to give as input only a string and a char.
The method should return a value between 0 and the length of the string - 1 if the char has been found or -1 if it is not there.
I know the actual 'indexOf' allows you to search for a string too, but this method is simplified.
I tried this but it's quite stupid since I used the real indexOf:
public static int indexOf(String s, char c){
if(s.indexOf(c) < 0){ // I'd like to change this
return -1;
}
if (s.length() == 0) //base case #1
{
return -1;
}
else if (s.charAt(0) == c) //base case #2
{
return 0;
}
else {
return 1 + indexOf(s.substring(1), c);
}
}
I saw this in particular, but is it possibile to write it without variables? Thanks
If you don't want local variables, you need to do the recursion in an internal method.
Advantage is that it's a lot faster, since it doesn't have to create new String objects, and the logic is tail-recursive, if used with a language that optimizes that.
public static int indexOf(String s, char c) {
return indexOf0(s, c, 0);
}
private static int indexOf0(String s, char c, int index) {
if (index == s.length())
return -1;
if (s.charAt(index) == c)
return index;
return indexOf0(s, c, index + 1);
}
The answer that you linked seems to be a good one... I recommend simply replacing the instances of the variable used in it with the method call the variable stores.
Below I simply edit the code:
public static int indexOf(char ch, String str) {
// Returns the index of the of the character ch
if (str == null || str.equals("")) {
// base case: no more string to search; return -1
return -1;
} else if (ch == str.charAt(0)) {
// base case: ch is at the beginning of str; return 0
return 0;
}
return indexOf(ch, str.substring(1)) == -1 ? -1 : 1 + indexOf(ch, str.substring(1));
}
I am working on a project where I need to add below method in SampleQueue class - .
public static boolean isValid(String s)
Above method should do this - It will take a String as an input
parameter. Consider strings that can be split so that their first half
is the same as their second half (ignoring blanks, punctuation, and
case). For example, the string "treetree" can be split into "tree" and
"tree". Another example is "world, world". After ignoring blanks and
the comma, the two halves of the string are the same. However, the
string "kattan" has unequal halves, as does the string "abcab".
Basically my method should return true when string has the property above and false otherwise. We need to only use methods in SampleQueue class as shown below to implement the method:
public class SampleQueue<T> {
private T[] queue;
private int frontIndex;
private int backIndex;
private static final int DEFAULT_INITIAL_CAPACITY = 200;
public SampleQueue() {
this(DEFAULT_INITIAL_CAPACITY);
}
public SampleQueue(int initialCapacity) {
T[] tempQueue = (T[]) new Object[initialCapacity + 1];
queue = tempQueue;
frontIndex = 0;
backIndex = initialCapacity;
}
public void enqueue(T newEntry) {
ensureCapacity();
backIndex = (backIndex + 1) % queue.length;
queue[backIndex] = newEntry;
}
public T getFront() {
T front = null;
if (!isEmpty())
front = queue[frontIndex];
return front;
}
public T dequeue() {
// some stuff here
}
private void ensureCapacity() {
// some stuff here
}
public boolean isEmpty() {
// some stuff here
}
public void clear() {
// some stuff here
}
public static boolean isValid(String s) {
if (s == null || s.isEmpty()) {
return false;
}
SampleQueue<Character> myQueue = new SampleQueue<>();
for (char ch : s.trim().toLowerCase().toCharArray()) {
if ((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9'))
myQueue.enqueue(ch);
}
// all is this right way to check the length?
if (myQueue.queue.length % 2 == 1) {
return false;
}
// now I am confuse here?
}
}
I implemented few things in the isValid method basis on this logic I came up with but I am confuse on what to do for the case length is even?
Enqueue all of the string’s characters—excluding blanks and
punctuation—one at a time. Let the length of the queue be n. If n is
odd, return false. If n is even then what should I do?
This seems overly complicated; use a regular expression to remove everything not a letter and then test if the two halves of the String are equal. Like,
public static boolean isValid(String s) {
String t = s.replaceAll("[^A-Za-z]", "");
return t.substring(0, t.length() / 2).equals(t.substring(t.length() / 2, t.length()));
}
Consider 4 input fields A, B, C and D on a web surface. The user can fill any of these arbitrary. There are 16 combinations of how to fill these fields. The ones allowed are:
A B C D
-------
1 0 0 0
1 1 0 0
1 1 1 0
1 1 1 1
where 1 means not null and 0 means null.
I am using the MVC pattern with jsf. I don't want the logic to be in the view, but rather in the controller. What is the best way to check this in Java?
I implemented two solutions so far:
Solution 1:
#Override
public boolean isInputInvalid(Integer a, Integer b, Integer c, Integer d) {
if (isNotSet(a) && isNotSet(b) && isNotSet(c) && isNotSet(d) {
return true;
}
return (firstParameterDoesNotExistAndSecondDoesExist(a, b)) || (firstParameterDoesNotExistAndSecondDoesExist(b, c)) || (firstParameterDoesNotExistAndSecondDoesExist(c, d));
}
private boolean firstParameterDoesNotExistAndSecondDoesExist(Integer firstParameter, Integer secondParameter) {
return isNotSet(firstParameter) && !isNotSet(secondParameter);
}
private boolean isNotSet(Integer parameter) {
return parameter == null;
}
Solution 2:
public boolean isInputValid(Integer a, Integer b, Integer c, Integer d) {
if (exists(a) && !exists(b) && !exists(c) && !exists(d) || //
exists(a) && exists(b) && !exists(c) && !exists(d) || //
exists(a) && exists(b) && exists(c) && !exists(d) || //
exists(a) && exists(b) && exists(c) && exists(d)) {
return true;
}
return false;
}
private boolean exists(Integer level) {
return level != null;
}
Note:
The first methods checks if input is invalid, while the second checks if input is valid (note the names of the methods).
I wrote 16 unit test cases, which all run green with both versions.
Do you have any hints/tips/tricks on how to get the code even more readable?
Valid combinations are: 1000, 1100, 1110 and 1111
If you only care about readability:
public static List<String> validOptions = Arrays.asList("1000","1100","1110","1111");
public boolean isValid(Integer a, Integer b, Integer c, Integer d)
{
StringBuilder sb = new StringBuilder();
sb.append(a==null ? 0 : 1);
sb.append(b==null ? 0 : 1),
sb.append(c==null ? 0 : 1);
sb.append(d==null ? 0 : 1);
return validOptions.contains(sb.toString());
}
Note that this is not the fastest or cleanest solution (wastes some CPU and memory)
To solve this for an arbitrary number of parameters, pass in true or false (if not null / null) in this:
static boolean isValid(boolean... params) {
boolean set = true;
for (boolean param : params) {
if (!set && param) return false;
set = param;
}
return params[0];
}
Or much cooler (and IMHO readable), but less performant, use regex on the array's toString():
static boolean isValid(boolean... params) {
return Arrays.toString(params).matches("\\[true(, true)*(, false)*]");
}
which ever implementation you use, you would call it like:
if (isValid(a != null, b != null, c != null, d != null))
Not fancy but fast and simple:
static boolean isValid(boolean a, boolean b, boolean c, boolean d) {
return a && (b || !c) && (c || !d);
}
Call:
isValid(a != null, b != null, c != null, d != null);
I don't really understand why you need this. Rather than a method that tests if input is valid, it would be much better to only allow valid input in the first place.
// This method is private, so you can't call it with arbitrary arguments.
private void privateMethod(Integer a, Integer b, Integer c, Integer d) {
// do something();
}
public void method(int a) {
privateMethod(a, null, null, null);
}
public void method(int a, int b) {
privateMethod(a, b, null, null);
}
public void method(int a, int b, int c) {
privateMethod(a, b, c, null);
}
public void method(int a, int b, int c, int d) {
privateMethod(a, b, c, d);
}
The way to modify this to any number of arguments (not just 4) is to have a method with signature
public void method(int... a)
Then, if the length of the array passed is less than the required length, you can just use null for the remaining inputs.
If this does not address your problem, I think you should consider editing your question to give an example of your use case, because I suspect there is a better way to achieve what you require.
You could create a pattern with a two dimensional array.
The advantage is that it is easy to adjust, and add additional information to it.
Here is a tiny example with your conditions.
In the end all you have to read is the pattern that is initialized in the static block, which is quite easy to read.
// Every boolean array in a dimension represents a valid pattern
private static boolean[][] pattern;
static {
pattern = new boolean[4][4];
pattern[0] = new boolean[]{true, false, false, false};
pattern[1] = new boolean[]{true, true, false, false};
pattern[2] = new boolean[]{true, true, true, false};
pattern[3] = new boolean[]{true, true, true, true};
}
public static void main(String[] args) {
// Testing an invalid combination
System.out.println(test(new Integer[]{1,null,3,null}));
// Testing a valid combination
System.out.println(test(new Integer[]{1,2,3,null}));
}
private static boolean test(Integer[] input) {
// cast the input to a boolean array that can be compared to the pattern.
boolean[] arr = createArr(input);
for(int i = 0;i<pattern.length;++i) {
if(Arrays.equals(pattern[i], arr)) { // Check if the pattern exists in the list of valid pattern. If it exists, then this is a valid combination
return true;
}
}
// the loop never found a valid combination, hence it returns false.
return false;
}
// This is just a helping method to create a boolean array out of an int array. It casts null to true and !null to false.
private static boolean[] createArr(Integer[] input) {
boolean[] output = new boolean[input.length];
for(int i = 0;i<input.length; ++i) {
output[i] = input[i] != null;
}
return output;
}
Yet another solution. Involves more code but for me it's easier to understand:
boolean isInputInvalid(Object ... args) {
int notNullDataIndex = -1;
for (int i = args.length - 1; i >= 0; i--) {
if (args[i] != null) {
notNullDataIndex = i;
break;
}
}
if (notNullDataIndex < 0) return false;
for (int i = notNullDataIndex; i >= 0; i--) {
if (args[i] == null) return false;
}
return true;
}
I would like to know if is possibile re-write an if like this
int var = 0;
if ( var == 1 || var == 2 )
{
//...
}
in somethings like this
int var = 0;
if ( var == (1 || 2) )
{
//...
}
or similar. Thanks
|| stands for or operator so it needs a condition on both of its sides so this is incorrect
as you are putting integer on both the sides of the || operator
According to the Java Language Specification
Each operand of the conditional-or operator must be of type boolean or Boolean, or a compile-time error occurs.
so no, there is no better (and faster) way to code your condition.
(The same rules apply to the conditional-and operator)
There is no such syntax with if in java.
If you have a large set of values in the if condition, you may use switch instead:
int var = ...;
switch(var) {
case 1:
case 2:
// ...
break;
default:
//else case
break;
}
Edit:
With Java 8, you can also write:
int var = ...;
if (IntStream.of(1, 2, 3, 4).anyMatch(i -> var == i)) {
//...
}
No, that is not possible in Java. What you're asking is something similar to sql IN operator.
if(var == (1 || 2)) could easily be translated to if(var IN [1,2]), but Java doesn't suport that either.
As close you can get to is to use a collection :
if(Arrays.asList(1,2).contains(var)){
or a String
if("1_OR_2".contains(String.valueOf(var))
One other approach could be to build a function like
public static final boolean in(final int var, final int... vals) {
for (int val : vals) {
if (var == val) {
return true;
}
}
return false;
}
And then, you'll call : if(in(var,1,2)){ .
Or you could build a wrapper for Integer, and add in method there, so the method call may sound more natural( if value x in [val1,val2 ... valN])
public final class Int {
private final Integer val;
public Int(final int val) {// avoid passing nulls
this.val = val;
}
public boolean in(final int... vals) {
for (int val : vals) {
if (this.val.equals(val)) {
return true;
}
}
return false;
}
public static void main(final String[] args) {
System.out.println(new Int(1).in(1, 2, 3));
}
}