Why is the function being called multiple times in a loop?

那年仲夏 提交于 2019-12-11 12:05:10

问题


I've made a graphical calculator app using the Processing Development Environment and have incorporated a Java Operation class. Then I called instances of the Operation class in my main file - calculator.pde. When I call the method on the multiple instances, conditionally, it prints output from the method multiple times because of the loop and conditional from which the method is called.

Here's the calculate() method of Operation class:

String calculate() {
    int operationIndex = userInput.indexOf(operationSymbol);
    ArrayList<String> clickedNumbers = new ArrayList<String>();
    System.out.println(operation + " index: " + operationIndex);
    for (int i = 0; i < operationIndex; i++) {
      clickedNumbers.add(userInput.get(i));         }
    double double1 = calculator.stringToDouble(String.join("", clickedNumbers)); 
    System.out.println("double1: " + double1);
    clickedNumbers.clear();
    int equalsIndex = userInput.indexOf("=");
    for (int i = operationIndex + 1; i < equalsIndex; i++) {
      clickedNumbers.add(userInput.get(i));
    }
    double double2 = calculator.stringToDouble(String.join("", clickedNumbers)); 
    System.out.println("double2: " + double2);
    Double operResult = this.doOperation(double1, double2);
    String operationResult = calculator.doubleToString(operResult);
    System.out.println("Operation Result: " + operationResult);
    return operationResult;
}

All System.out.println() statements depend on local variables inside the method. These are what should be printing out to the console only once. Whenever the user puts in an operation and presses equals, for example, if s/he inputs 15 * 3, it outputs:

Above, the highlighted part of the console output is my desired output.

Here is my code where the calculate() method is called:

  String[] numberStr = {"1", "2", "3", "4", "5", "6", "7", "8", "9"};
  Boolean pressedEquals = listName.contains("=");

  for(String number : numberStr) {
  Boolean pressedNumber = listName.contains(number);
    if (pressedNumber && pressedEquals) {
      if (listName.contains("+")) {
        processStatement = "Adding Numbers...";
        result = addition.calculate();
      }
      else if (listName.contains("-")) {
        processStatement = "Subtracting Numbers...";
        result = subtraction.calculate();
      }
      else if (listName.contains("*")) {
        processStatement = "Multiplying Numbers...";
        result = multiplication.calculate();
      }
      else if (listName.contains("/")) {
        processStatement = "Dividing Numbers...";
        result = division.calculate();
      }
      else if (listName.contains("%")) {
        processStatement = "Modulufying Numbers...";
        result = modulus.calculate();
      }
      else if (listName.contains("^")) {
        processStatement = "Expounding numbers...";
        result = exponential.calculate();
      }
    } 
  }

I don't understand why it is printing output as many times as the length of the userInput ArrayList. I know the problem is the pressedNumber Boolean in the for loop. I know the OP on this question had the same problem, with it the printing a number of times depending on a length of user input, but the answer to the question did not explain why it was doing this.

Research and Trials that didn't work

Part of fixing this was making the processStatement into a variable because earlier I just printed it inside the condition. This didn't work because it printed multiple times. I cannot do this for the println statements inside the method because they depend on the variables inside the method, and there are quite a few statements. My second plan was to make a static method printInfo(), but this also wouldn't have worked because of the variables being too tightly scoped, and I can't define them outside because then that would be inaccurate.

Update

I have looked more on stack overflow, this time for regular expressions, and these questions added to my research to solve this problem:

  • This one for making the regular expression that I am looking for
  • This question for checking if the expression matches the regular expression
  • This question to extract a part of the regEx for later code (my control flow)
  • The answer to this question that makes characters with special meaning be used as regular characters by prepending them with \\

回答1:


Here are a few things that you might want to reconsider in your code:

For example, take a look at this snippet:

String[] numberStr = {"1", "2", "3", "4", "5", "6", "7", "8", "9"};
Boolean pressedEquals = listName.contains("=");

for(String number : numberStr) {
    Boolean pressedNumber = listName.contains(number);
    // ...
}

You don't need this loop here. You can simply validate the listName that it contains digits, operators or not i.e. it is a valid expression. And, then simply call the calculate() method if it is valid. You may also use regex-based validation to enforce your particular expression format.

Skipping that loop and after performing validation, it would look like this:

// Validate expression format here
// Example: <number> <operator> <number> <=>
//             1          *        5      =

final boolean isValidated = isValidExpression( /* expression */ );

if ( isValidated == true )
{
    final String op = /* get operator here */;
    switch ( op )
    {
        case "+":
            result = addition.calculate();
            break;

        case "-":
            result = subtraction.calculate();
            break;

       // ... /, *, % ...

        default:
            // ERROR: Invalid operator...
    }
}

Apart from this, you may use stack-based expression evaluation too.


UPDATE:

Here's an example of isValidExpression() method with regex:

// Test to validate expression with regex
// Example: <number> <operator> <number> <=>
//             1          *        5      =

import java.util.regex.Matcher;
import java.util.regex.Pattern;

class ExpressionValidator
{
    public static boolean isValidExpression( final String exp )
    {
        final String regex = "\\d+\\s*[*|/|+|-]\\s*\\d+\\s*[=]";
        final Pattern pattern = Pattern.compile( regex );
        final Matcher matcher = pattern.matcher( exp.trim() );
        return matcher.find();
    }

    public static void main( final String[] args )
    {
        final String[] expressions = 
        {  
            " 1 +  2 =",
            " 3 *  5 =",
            "12 + 10 =",
            " 33 = 25 ",
            " +65  65 ",
            "45 666  ="
        };

        for ( final String exp : expressions )
        {
            System.out.println( "[" + exp + "] >> " + isValidExpression( exp ) );
        }
    }
}

Output:

[ 1 +  2 =] >> true
[ 3 *  5 =] >> true
[12 + 10 =] >> true
[ 33 = 25 ] >> false
[ +65  65 ] >> false
[45 666  =] >> false

Here's the live example: https://ideone.com/S9Wf9b



来源:https://stackoverflow.com/questions/51996320/why-is-the-function-being-called-multiple-times-in-a-loop

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!