Reputation: 138
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?
Upvotes: 3
Views: 445
Reputation: 4496
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).
Upvotes: 0
Reputation: 781
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
Upvotes: 0
Reputation: 1384
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();
Upvotes: 0
Reputation: 45309
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;
}
Upvotes: 3
Reputation: 44388
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;
Upvotes: 0