Home > Enterprise >  How to calculate multi-operator of list in dart?
How to calculate multi-operator of list in dart?

Time:02-25

I have a list of num and string of operator above:

final List<dynamic> items = [5.0, "-", 2, "*", 3];

I want to calculate the value inside of it. I can do like this:

  final List<dynamic> items = [5.0, "-", 2, "*", 3]; //correct is -1
  num result = 0;
  String op = " ";
  for (final item in items) {
    if (item is String) {
      op = item;
    }
    if (item is num) {
      switch (op) {
        case " ":
          result = result   item;
          break;
        case "-":
          result = result - item;
          break;
        case "*":
          result = result * item;
          break;
        case "/":
          result = result / item;
          break;
      }
    }
  }
  print(result); // incorrect result: 9

As above code, If it is just an " " or "-" operator it would return the correct answer, but because of the order of operators "/" and "*" doing like above return incorrect result.

Can anyone suggest any algorithm?

CodePudding user response:

Here is one way of doing it, the code works but I didn't put the tests that would be necessary to check for bad input.

// functions for basic operations
num multiply(num leftOp, num rightOp) => leftOp * rightOp;
num divide(num leftOp, num rightOp) => leftOp / rightOp;
num add(num leftOp, num rightOp) => leftOp   rightOp;
num substract(num leftOp, num rightOp) => leftOp - rightOp;

void main() {
  final List<dynamic> items = [5.0, "-", 2, "*", 3]; //correct is -1

  num result = 0;

  // Copy the list in a temporary list
  var calc = [...items];

  // set the precedence order of the operators
  // create 2 groups of equal importance
  var operators = [
    {
      "*": multiply,
      "/": divide,
    },
    {
      " ": add,
      "-": substract,
    }
  ];

  //calc.reduce((value, element) => value   element);

  // loop until all operators have produced result
  while (calc.length > 1) {
    for (var opPrecedence in operators) {
      
      // find first operator in a group, starting from left
      var pos = calc.indexWhere((e) => opPrecedence.containsKey(e));

      if (pos >= 0) {
        num leftOp = calc[pos - 1];
        num rightOp = calc[pos   1];

        var operation = opPrecedence[calc[pos]];

        result = operation!(leftOp, rightOp);

        // remove the 2 operands and replace with result
        calc.removeAt(pos);
        calc.removeAt(pos);
        calc[pos - 1] = result;
      }
    }
  }

  // what should be left is the final result
  print(calc[0]);
}

CodePudding user response:

By combined ManuH68 answer I did:

void main() {
test('Return correct', () {
const correctResult = 10;
final calc = <dynamic>[2, "*", 5, "/", 2, "-", 3, " ", 8];
num result = 0;

// clean "*" and "/" first
while (calc.contains("*") || calc.contains("/")) {
  final pos = calc.indexWhere((e) => e == "*" || e == "/");
  num leftOp = calc[pos - 1];
  num rightOp = calc[pos   1];
  switch (calc[pos]) {
    case "*":
      result = leftOp * rightOp;
      break;
    case "/":
      result = leftOp / rightOp;
      break;
  }
  calc.removeAt(pos);
  calc.removeAt(pos);
  calc[pos - 1] = result;
}

// Then After calculated "*" and "/" perform calculate on " " and "-"
while (calc.length > 1) {
  final pos = calc.indexWhere((e) => e == "-" || e == " ");
  num leftOp = calc[pos - 1];
  num rightOp = calc[pos   1];
  switch (calc[pos]) {
    case "-":
      result = leftOp - rightOp;
      break;
    case " ":
      result = leftOp   rightOp;
      break;
  }
  calc.removeAt(pos);
  calc.removeAt(pos);
  calc[pos - 1] = result;
}

  expect(calc[0], correctResult);
});
}

this might not clean but this is what I founded that work

  • Related