【问题标题】:Compare value of enum比较枚举的值
【发布时间】:2018-09-13 19:30:09
【问题描述】:

实现一个中缀到后缀计算器,需要检查一个运算符的优先级是否低于另一个。到目前为止,这是我所拥有的:

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
}

我尝试了许多不同的方法来检查传入的字符的优先级,但无济于事。有没有一种简单的方法来比较枚举的两个值?我必须创建一个循环吗?

【问题讨论】:

  • 顺便说一句:为什么isOperatorisLowerPrecedence 方法声明为private?从问题中的代码开始,它们未使用。
  • @LuCio 它们在我的算法中用于将中缀转换为我尚未发布的后缀,这有助于发布很多吗?
  • 我只是好奇它们是否被使用过。现在我知道了。

标签: java enums


【解决方案1】:

如果您有一个将“运算符”char 转换为枚举值的方法,则很容易进行比较。

例如:

static Operators getOperatorForChar(char op) {
    for(Operators val: values())
        if(op == val.operator)
            return val; //return enum type

    return null;
}

然后您可以使用以下方法实现您的方法:

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;
}

【讨论】:

  • 我认为没有必要为此创建一个全新的方法。你能看看my answer,告诉我你的想法吗?我感谢不同开发人员的见解:) 提前致谢。
  • @lealceldeiro 我明白了...但是Enum 提供的valueOf 方法需要一个字符串文字名称,例如"ADD""SUBTRACT" 等。要从operator 转换对于其中一个值,需要不同的查找逻辑。
  • 哦,我明白了。我在 OP 中考虑使用这种方法,就像这样:Operators.isLowerPrecedence('+', '-')。不过,你说的完全有道理。感谢您的反馈。
  • 需要从 isLowerPrecedence 中删除静态关键字!
  • @Loc 在这种情况下不是。但是在另一种设计中,是的,我们可以将其设为实例方法并使其仅采用 one char 参数(将当前运算符与参数进行比较)。但是这个逻辑是静态的是有意义的,尽管方法名可以改进。
【解决方案2】:

您可以循环枚举的值以匹配正确的运算符并比较其优先级:

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);
}

在未找到运算符时返回 boolean 可能会造成混淆。我建议你在这种情况下抛出异常。

...
if (first == null || second ==null) throw new Exception("Operator not found.");
return first < second;

【讨论】:

    【解决方案3】:

    或者,您可以像这样比较优先级:

    private static boolean isLowerPrecedence(Operators operatorFirst, Operators operatorSecond) {
        if(operatorFirst.getPrecedence() < operatorSecond.getPrecedence()){
            return true;
        } else {
            return false;
        }
    }
    

    当然也可以写成:

    return operatorFirst.getPrecedence() < operatorSecond.getPrecedence();
    

    【讨论】:

    • if (condition) return true; else return false; 可以简化为return condition;
    • 顺便说一句,在 OP 示例中,isLowerPrecedence 期望 char 而不是 Operators 作为参数(尽管有这样的重载版本可能会很好)。
    • @Pshemo ,啊,好吧 - 我知道return(condition) 是一个快捷方式,但我想尽可能地编写最易读的代码。关于 chars 作为参数,我认为(我个人认为)这是代码中不必要的复杂性。
    【解决方案4】:

    通过查看this question,您可以通过ComparableComparator 接口了解Java 句柄类型比较。

    当然,它们适用于比这个更复杂的情况,但我认为您应该考虑到它们,以便您可以看到处理标准 Java 库提供的一组排序算法的正确方法。

    由于您不能覆盖默认 Enum 的 compareTo(它被声明为 final),因此您可以实现自己的 Comparator:

    public class OperatorsComparator implements Comparator<Operators> {
    
        @Override
        public int compare(Operators o1, Operators o2) {
            return o1.getPrecedence() - o2.getPrecedence();
        }
    }
    

    那么您将需要某种方式从您提供的char 中找到正确的Operators 值:

    private static Operators findOperator(char c){
        for(Operators op : Operators.values()){
            if(op.getOperator() == c)
                return op;
        }
        return null;
    }
    

    通过在两个优先级和之前的 Operators 查找器之间使用减法,您可以像这样实现您的 isLowerPrecedence 方法:

    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;
    }
    

    通过这种方式比较优先级,您会发现o1 将被标记为较低优先级,即使它与o2 具有相同的优先级,这是默认行为。 请注意您尝试用作运算符的字符,因为如果出现任何问题,您需要捕获 Exception

    执行示例:

    System.out.println(isLowerPrecedence('+', '-'));
    System.out.println(isLowerPrecedence('+', '*'));
    System.out.println(isLowerPrecedence('/', '-'));
    System.out.println(isLowerPrecedence('/', '*'));
    System.out.println(isLowerPrecedence('*', '-'));
    

    打印这些消息:

    true
    true
    false
    true
    false
    

    【讨论】:

      【解决方案5】:

      您可以使用this answer of mine中提出的EnumLookup帮助类(那里有EnumLookup的源代码)。

      重新设计您的 Operators 枚举(我强烈建议使用单数类名)后,您会得到:

      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();
      }
      

      这种方法的主要缺点是您的charboxed 转换为Character,但除非性能对您的应用程序至关重要,否则我不会担心这一点(可读性应该更重要)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-01-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-04
        • 2023-03-09
        • 2023-03-17
        相关资源
        最近更新 更多