将字符串计算为 Double(后缀表示法)
Evaluate String to Double (Postfix-notation)
我想创建一个方法,以后缀表示法解释此列表(方法“单词”将字符串拆分为单词列表,单词列表由 \s 分隔。)。这就是我得到的,我想知道是否有更短的方法来解决这个问题,因为我经常在那里重复自己。
public static double eval(String expr) {
return eval_(new ListStack<Double>() , words(expr));
}
private static double eval_(Stack<Double> s, List<String> expr) {
if (expr.isEmpty()) {
return s.top();
} else if (expr.head().equals("+")) {
Double fstValue = s.top();
s = s.pop();
Double sndValue = s.top();
s = s.pop();
s = s.push(add.apply(fstValue).apply(sndValue));
return eval_(s, expr.tail());
} else if (expr.head().equals("-")) {
Double fstValue = s.top();
s = s.pop();
Double sndValue = s.top();
s = s.pop();
s = s.push(sub.apply(fstValue).apply(sndValue));
return eval_(s, expr.tail());
} else if (expr.head().equals("*")) {
Double fstValue = s.top();
s = s.pop();
Double sndValue = s.top();
s = s.pop();
s = s.push(mul.apply(fstValue).apply(sndValue));
return eval_(s, expr.tail());
} else if (expr.head().equals("/")) {
Double fstValue = s.top();
s = s.pop();
Double sndValue = s.top();
s = s.pop();
s = s.push(div.apply(fstValue).apply(sndValue));
return eval_(s, expr.tail());
} else if (expr.head().equals("^")) {
Double fstValue = s.top();
s = s.pop();
Double sndValue = s.top();
s = s.pop();
s = s.push(pow.apply(fstValue).apply(sndValue));
return eval_(s, expr.tail());
} else if (expr.head().equals("!")) {
Double fstValue = s.top();
s = s.pop();
s = s.push(fact.apply(fstValue));
return eval_(s, expr.tail());
} else {
Double value = Double.parseDouble(expr.head());
s = s.push(value);
return eval_(s, expr.tail());
}
}
我试着把它缩短一点:
private static double eval_(Stack<Double> s, List<String> expr) {
Double fstValue;
Double sndValue;
if (expr.isEmpty()) {
return s.top();
} else if (!expr.isEmpty()) {
fstValue = s.top();
s = s.pop();
sndValue = s.top();
s = s.pop();
if (expr.head().equals("+") && !expr.isEmpty()) {
s = s.push(add.apply(fstValue).apply(sndValue));
return eval_(s, expr.tail());
} else if (expr.head().equals("-") && !expr.isEmpty()) {
s = s.push(sub.apply(fstValue).apply(sndValue));
return eval_(s, expr.tail());
} else if (expr.head().equals("*") && !expr.isEmpty()) {
s = s.push(mul.apply(fstValue).apply(sndValue));
return eval_(s, expr.tail());
} else if (expr.head().equals("/") && !expr.isEmpty()) {
s = s.push(div.apply(fstValue).apply(sndValue));
return eval_(s, expr.tail());
} else if (expr.head().equals("^") && !expr.isEmpty()) {
s = s.push(pow.apply(fstValue).apply(sndValue));
return eval_(s, expr.tail());
} else if (expr.head().equals("!") && !expr.isEmpty()) {
s = s.push(fact.apply(fstValue));
return eval_(s, expr.tail());
}
else {
Double value = Double.parseDouble(expr.head());
s = s.push(value);
return eval_(s, expr.tail());
}
} else {
Double value = Double.parseDouble(expr.head());
s = s.push(value);
return eval_(s, expr.tail());
}
}
Edit:
Input:
System.out.println(eval(5 6 + 8 *));
'Interpreted as (5+6) * 8 = 11 * 8'
Output: "88"
private static final Function<Double, Function<Double, Double>> add = x -> y -> x + y;
private static final Function<Double, Function<Double, Double>> sub = x -> y -> x - y;
private static final Function<Double, Function<Double, Double>> mul = x -> y -> x * y;
private static final Function<Double, Function<Double, Double>> div = x -> y -> x / y;
private static final Function<Double, Function<Double, Double>> pow = x -> y -> Math.pow(x,y);
private static final Function<Double, Double> fact = Postfix::fact;
public static double fact(double i){
return i > 1 ? i * fact(i - 1) : 1;
}
它既不工作也不短。 (我的教授告诉我我可以一行完成)。
感谢您帮助我!
编辑 2:我尝试了@Rocco 的回答(并使用 IntelliJ 简化了它)
private static double eval(String expr) {
switch (expr) {
case "+" -> s.push(add.apply(s.popTop().fst).apply(s.popTop().fst));
case "-" -> s.push(sub.apply(s.popTop().fst).apply(s.popTop().fst));
case "*" -> s.push(mul.apply(s.popTop().fst).apply(s.popTop().fst));
case "/" -> s.push(div.apply(s.popTop().fst).apply(s.popTop().fst));
case "^" -> {
double exp = s.popTop().fst;
s.push(Math.pow(s.popTop().fst, exp));
}
case "!" -> {
s.push(fact.apply(s.popTop().fst));
}
default -> s.push(Double.valueOf(String.valueOf(expr)));
}
return s.popTop().fst;
}
它总是抛出“NumberFormatException”。 (可能是因为它无法将“+”解析为 Double)
我做了什么
- 我用
switch
-case
替换了 if
-else
语句(我不必使用 break
,因为我 return
.
- 我删除了不必要的
else
-语句(如果您已经在 if
-语句中返回,请不要使用它们)。
- 我提取了一个名为“evalSingle”的方法(您必须将 ??? 替换为
add
、sub
... 中的任何内容)。
代码
private static double eval_(Stack <Double> s, List <String> expr) {
if (expr.isEmpty()) {
return s.top();
} else if (!expr.isEmpty()) {
switch (expr.head()) {
case "+":
return evalSingle(s, expr, add);
case "-":
return evalSingle(s, expr, sub);
case "*":
return evalSingle(s, expr, mul);
case "/":
return evalSingle(s, expr, div);
case "^":
return evalSingle(s, expr, pow);
case "!":
return evalSingle(s, expr, fact);
}
}
Double value = Double.parseDouble(expr.head());
s = s.push(value);
return eval_(s, expr.tail());
}
private static double evalSingle(Stack <Double> s, List <String> expr, ??? operator) {
Double fstValue = s.top();
s = s.pop();
Double sndValue = s.top();
s = s.pop();
s = s.push(operator == fact ? operator.apply(fstValue) : operator.apply(fstValue).apply(sndValue));
return eval_(s, expr.tail());
}
我认为你的教授在开玩笑,但是,是的,你把它变短了(不是一行,除非你删除所有的 LF)。
只是为了解释一下,这是 shift-reduce 解析器的最小实现,当你有一个数字时,只需将它推入堆栈(shift),当运算符用操作结果替换最顶层的操作数时。
请注意,我不会在此处检查错误,因此不正确的表达式可能会 return 产生错误的值。
import java.util.Stack;
public class PostFixEprParser {
public static double eval(String expr) {
Stack<Double> s=new Stack<>();
for (String token: expr.split("\s+")) {
switch (token) {
case "+":
s.push(s.pop()+s.pop());
break;
case "-":
s.push(s.pop()-s.pop());
break;
case "*":
s.push(s.pop()*s.pop());
break;
case "/":
s.push(s.pop()/s.pop());
break;
case "^":
{
double exp=s.pop();
s.push(Math.pow(s.pop(), exp));
}
break;
case "!":
//TODO Here define your factorial function s.push(fact(s.pop()));
break;
default:
s.push(Double.valueOf(token));
}
}
return s.pop();
}
我想创建一个方法,以后缀表示法解释此列表(方法“单词”将字符串拆分为单词列表,单词列表由 \s 分隔。)。这就是我得到的,我想知道是否有更短的方法来解决这个问题,因为我经常在那里重复自己。
public static double eval(String expr) {
return eval_(new ListStack<Double>() , words(expr));
}
private static double eval_(Stack<Double> s, List<String> expr) {
if (expr.isEmpty()) {
return s.top();
} else if (expr.head().equals("+")) {
Double fstValue = s.top();
s = s.pop();
Double sndValue = s.top();
s = s.pop();
s = s.push(add.apply(fstValue).apply(sndValue));
return eval_(s, expr.tail());
} else if (expr.head().equals("-")) {
Double fstValue = s.top();
s = s.pop();
Double sndValue = s.top();
s = s.pop();
s = s.push(sub.apply(fstValue).apply(sndValue));
return eval_(s, expr.tail());
} else if (expr.head().equals("*")) {
Double fstValue = s.top();
s = s.pop();
Double sndValue = s.top();
s = s.pop();
s = s.push(mul.apply(fstValue).apply(sndValue));
return eval_(s, expr.tail());
} else if (expr.head().equals("/")) {
Double fstValue = s.top();
s = s.pop();
Double sndValue = s.top();
s = s.pop();
s = s.push(div.apply(fstValue).apply(sndValue));
return eval_(s, expr.tail());
} else if (expr.head().equals("^")) {
Double fstValue = s.top();
s = s.pop();
Double sndValue = s.top();
s = s.pop();
s = s.push(pow.apply(fstValue).apply(sndValue));
return eval_(s, expr.tail());
} else if (expr.head().equals("!")) {
Double fstValue = s.top();
s = s.pop();
s = s.push(fact.apply(fstValue));
return eval_(s, expr.tail());
} else {
Double value = Double.parseDouble(expr.head());
s = s.push(value);
return eval_(s, expr.tail());
}
}
我试着把它缩短一点:
private static double eval_(Stack<Double> s, List<String> expr) {
Double fstValue;
Double sndValue;
if (expr.isEmpty()) {
return s.top();
} else if (!expr.isEmpty()) {
fstValue = s.top();
s = s.pop();
sndValue = s.top();
s = s.pop();
if (expr.head().equals("+") && !expr.isEmpty()) {
s = s.push(add.apply(fstValue).apply(sndValue));
return eval_(s, expr.tail());
} else if (expr.head().equals("-") && !expr.isEmpty()) {
s = s.push(sub.apply(fstValue).apply(sndValue));
return eval_(s, expr.tail());
} else if (expr.head().equals("*") && !expr.isEmpty()) {
s = s.push(mul.apply(fstValue).apply(sndValue));
return eval_(s, expr.tail());
} else if (expr.head().equals("/") && !expr.isEmpty()) {
s = s.push(div.apply(fstValue).apply(sndValue));
return eval_(s, expr.tail());
} else if (expr.head().equals("^") && !expr.isEmpty()) {
s = s.push(pow.apply(fstValue).apply(sndValue));
return eval_(s, expr.tail());
} else if (expr.head().equals("!") && !expr.isEmpty()) {
s = s.push(fact.apply(fstValue));
return eval_(s, expr.tail());
}
else {
Double value = Double.parseDouble(expr.head());
s = s.push(value);
return eval_(s, expr.tail());
}
} else {
Double value = Double.parseDouble(expr.head());
s = s.push(value);
return eval_(s, expr.tail());
}
}
Edit:
Input:
System.out.println(eval(5 6 + 8 *));
'Interpreted as (5+6) * 8 = 11 * 8'
Output: "88"
private static final Function<Double, Function<Double, Double>> add = x -> y -> x + y;
private static final Function<Double, Function<Double, Double>> sub = x -> y -> x - y;
private static final Function<Double, Function<Double, Double>> mul = x -> y -> x * y;
private static final Function<Double, Function<Double, Double>> div = x -> y -> x / y;
private static final Function<Double, Function<Double, Double>> pow = x -> y -> Math.pow(x,y);
private static final Function<Double, Double> fact = Postfix::fact;
public static double fact(double i){
return i > 1 ? i * fact(i - 1) : 1;
}
它既不工作也不短。 (我的教授告诉我我可以一行完成)。 感谢您帮助我!
编辑 2:我尝试了@Rocco 的回答(并使用 IntelliJ 简化了它)
private static double eval(String expr) {
switch (expr) {
case "+" -> s.push(add.apply(s.popTop().fst).apply(s.popTop().fst));
case "-" -> s.push(sub.apply(s.popTop().fst).apply(s.popTop().fst));
case "*" -> s.push(mul.apply(s.popTop().fst).apply(s.popTop().fst));
case "/" -> s.push(div.apply(s.popTop().fst).apply(s.popTop().fst));
case "^" -> {
double exp = s.popTop().fst;
s.push(Math.pow(s.popTop().fst, exp));
}
case "!" -> {
s.push(fact.apply(s.popTop().fst));
}
default -> s.push(Double.valueOf(String.valueOf(expr)));
}
return s.popTop().fst;
}
它总是抛出“NumberFormatException”。 (可能是因为它无法将“+”解析为 Double)
我做了什么
- 我用
switch
-case
替换了if
-else
语句(我不必使用break
,因为我return
. - 我删除了不必要的
else
-语句(如果您已经在if
-语句中返回,请不要使用它们)。 - 我提取了一个名为“evalSingle”的方法(您必须将 ??? 替换为
add
、sub
... 中的任何内容)。
代码
private static double eval_(Stack <Double> s, List <String> expr) {
if (expr.isEmpty()) {
return s.top();
} else if (!expr.isEmpty()) {
switch (expr.head()) {
case "+":
return evalSingle(s, expr, add);
case "-":
return evalSingle(s, expr, sub);
case "*":
return evalSingle(s, expr, mul);
case "/":
return evalSingle(s, expr, div);
case "^":
return evalSingle(s, expr, pow);
case "!":
return evalSingle(s, expr, fact);
}
}
Double value = Double.parseDouble(expr.head());
s = s.push(value);
return eval_(s, expr.tail());
}
private static double evalSingle(Stack <Double> s, List <String> expr, ??? operator) {
Double fstValue = s.top();
s = s.pop();
Double sndValue = s.top();
s = s.pop();
s = s.push(operator == fact ? operator.apply(fstValue) : operator.apply(fstValue).apply(sndValue));
return eval_(s, expr.tail());
}
我认为你的教授在开玩笑,但是,是的,你把它变短了(不是一行,除非你删除所有的 LF)。
只是为了解释一下,这是 shift-reduce 解析器的最小实现,当你有一个数字时,只需将它推入堆栈(shift),当运算符用操作结果替换最顶层的操作数时。
请注意,我不会在此处检查错误,因此不正确的表达式可能会 return 产生错误的值。
import java.util.Stack;
public class PostFixEprParser {
public static double eval(String expr) {
Stack<Double> s=new Stack<>();
for (String token: expr.split("\s+")) {
switch (token) {
case "+":
s.push(s.pop()+s.pop());
break;
case "-":
s.push(s.pop()-s.pop());
break;
case "*":
s.push(s.pop()*s.pop());
break;
case "/":
s.push(s.pop()/s.pop());
break;
case "^":
{
double exp=s.pop();
s.push(Math.pow(s.pop(), exp));
}
break;
case "!":
//TODO Here define your factorial function s.push(fact(s.pop()));
break;
default:
s.push(Double.valueOf(token));
}
}
return s.pop();
}