Here is an answer that allows multiple operands and respects order of operations, unlike any of the others that are currently here.
import java.util.Arrays;
import java.util.List;
public class Expression {
private List<Integer> operands;
private List<Character> operators;
public Expression(List<Integer> operands, List<Character> operators) {
this.operands = operands;
this.operators = operators;
}
public Expression subExpression(int fromIndex, int toIndex) {
return new Expression(
operands.subList(fromIndex, toIndex),
operators.subList(fromIndex, toIndex - 1));
}
private int rightMost(char operator) {
return operators.lastIndexOf(operator);
}
public double evaluate() {
if (operands.size() == 1) {
return operands.get(0).doubleValue();
}
if (rightMost('+') > -1){
return subExpression(0, rightMost('+') + 1).evaluate()
+ subExpression(rightMost('+') + 1, operands.size()).evaluate();
}
if (rightMost('-') > -1){
return subExpression(0, rightMost('-') + 1).evaluate()
- subExpression(rightMost('-') + 1, operands.size()).evaluate();
}
if (rightMost('*') > -1){
return subExpression(0, rightMost('*') + 1).evaluate()
* subExpression(rightMost('*') + 1, operands.size()).evaluate();
}
if (rightMost('/') > -1){
return subExpression(0, rightMost('/') + 1).evaluate()
/ subExpression(rightMost('/') + 1, operands.size()).evaluate();
}
return 0;
}
@Override
public String toString() {
StringBuilder toReturn = new StringBuilder();
for (int index = 0; index < operands.size(); index++){
toReturn.append(operands.get(index));
toReturn.append(" ");
toReturn.append(
index == operators.size() ? "=" : operators.get(index));
toReturn.append(" ");
}
toReturn.append(evaluate());
return toReturn.toString();
}
public static Expression makeRandom(
int minimum, int maximum, int numberOfOperands) {
Integer[] operands = new Integer[numberOfOperands];
Character[] operators = new Character[numberOfOperands - 1];
for (int index = 0; index < numberOfOperands; index++) {
operands[index] = minimum
+ (int)(Math.random() * (maximum - minimum + 1));
}
for (int index = 0; index < numberOfOperands - 1; index++) {
operators[index] = "+-*/".charAt((int)(Math.random() * 4));
}
return new Expression(Arrays.asList(operands), Arrays.asList(operators));
}
public static void main (String[] args){
System.out.println(makeRandom(1, 10, 6));
System.out.println(new Expression(
Arrays.asList(1, 2, 3), Arrays.asList('+', '*')));
}
}
The main is just here for a quick and dirty test. Here is the output from one run of it. As you can see, 1 + 2 * 3 gives the correct answer - no other answer that is currently on this page gets this right.
10 / 5 / 6 * 9 + 9 * 1 = 12.0
1 + 2 * 3 = 7.0
I've made evaluate return double to avoid any nasty surprises with integer division. This could easily be changed if necessary. Also, there's no error handling here - there are a few methods that should do some error handling on their parameters, and something really should be done about capturing division by zero.
This works by splitting an expression into smaller subexpressions, evaluating each recursively, then bringing them back together. The magic is in the order of the operations in the evaluate method. The different operators have to be treated in this order, for these reasons.
+ has to be considered before -, so that a - b + c parses as (a - b) + c, not a - (b + c).
* has to be considered before /, so that a / b * c parses as (a / b) * c, not a / (b * c).
+ and - both have to be considered before * and /, so that * and / are evaluated first.
- Subtraction has to work from right to left, so that
a - b - c parses as (a - b) - c, not a - (b - c).
- Division has to work from right to left, so that
a / b / c parses as (a / b) / c, not a / (b / c).
- Addition and multiplication could be done from left to right or from right to left, but having written the
rightMost method, it made sense to do them from right to left.