JavaRush /Java Blog /Random-IT /Calcolatrice in Java con base di soli lvl 10 JavaRush (sf...

Calcolatrice in Java con base di soli lvl 10 JavaRush (sfida 3Kyu su CodeWars)

Pubblicato nel gruppo Random-IT
Un altro articolo sulle mie avventure su CodeWars. Per questo implementiamo la funzionalità di una calcolatrice elementare: crea una semplice calcolatrice che fornisca una stringa di operatori (), +, -, *, / . Calcolatrice in Java con base di solo livello 10 JavaRush (task 3Kyu su CodeWars) - 1Ho solo più di 10 livelli di JavaRush al mio attivo, quindi il codice è piuttosto complicato, ma funziona perfettamente. L'attività, come avrai notato, proviene dal sito Web CodeWars . Il suo grado è 3kyu . Posso darti il ​​link in un messaggio privato. Ecco un elenco parziale di metodi e processi che mi hanno aiutato:
  1. Ricorsione. Il processo in cui un metodo richiama se stesso (la prima volta che lo si utilizza :)) è necessario in questo caso per eliminare le parentesi.
  2. Metodi String'a trim(), split(), substring(), replace().
  3. Metodi di raccolta di base List.
  4. Così come la conversione del tipo Doubleda Stringe verso.
In linea di principio, questo è sufficiente. Prima di passare al codice vero e proprio, ti dirò in quali insidie ​​ho riscontrato. Per la maggior parte, questo è l'ordine in cui vengono eseguiti i calcoli, all'inizio ho creato uno schema standard * > / > + > -, ma mi sono reso conto che, ad esempio, con questa opzione: 12/6 * 32/2, il programma eseguirà prima la moltiplicazione ( 6*32) e tutto andrà in discesa, quindi l'ordine è diventato così: * > / > + > -. Dopo un altro paio d'ore mi sono imbattuto nel ciottolo più grande - -. In diverse posizioni e con diverse combinazioni, ha cambiato TUTTO . (Questo è, ovviamente, colpa mia, perché, ad esempio: -34, non si trova in una cella dell'elenco, ma in due: in una, - nell'altra, 34). Per questo motivo abbiamo dovuto scrivere 2 logiche aggiuntive nei calcoli con -, in generale, lo vedrai nel codice. Mi scuso per i commenti non necessari nel codice, volevo rivelare il più possibile il mio pensiero e spiegare cosa sta succedendo lì.
import java.util.*;

public class Calculator {
    public static void main(String[] args) {
        String num = "2 / ( ( 2 + 0 ) * 1 ) - 6";
        System.out.println(evaluate(num));
    }

    public static Double evaluate(String expression) {

//  Этап 1
//  На данном этапе преобразуем нашу строку в список строк, через совмещение цикла for-each и метода split(),
//  также используем метод trim(), чтобы избавиться от пробелов по краям.
//  Обратите внимание, что каждым вторым элиментом я добавляю " ". Для того, чтобы потом мне было легче работать со строкой

        List<string> strList = new ArrayList<>();
        for (String listElement : expression.trim().split(" ")) {
            strList.add(listElement);
            strList.add(" ");
        }
        strList.remove(strList.size() - 1);
//        for (String x : strList) System.out.print(x + "");
//        System.out.println();
//        После того, How дочитаете code до конца, расскоментируйте две верхние строчки
//        и посмотрите How работает рекрусия

//  Этап 2
//  Производим поиск символа "(" в списке если находим, то преобразуем все символы от '(' до последнего ')' в строку.
//  Надо быть внимательными и проверить на случай двух контрукций: 1) (())  2) ()().
//  P.S. После получения строки мы используем РЕКУРСИЮ (метод вызывает сам себя). Таким образом будем находить произведение скобок.

        if (strList.indexOf("(") != -1) {
//          Если "(" обнаружен, ищем подходящую конструкцию используя цикл.

            for (int i = strList.indexOf("(") + 1; i < strList.size() - 1; i++) {
//
//              Конструкция 1: первым элиментом, который мы отыскали были вторые "("
                String recursion = "";
                if (strList.get(i).equals("(")) {
                    for (int j = i; j < strList.lastIndexOf(")"); j++) {
                        recursion += strList.get(j);
                    }
                    // сверху считывали последовательность находящуюся в скобках (()) До lastIndex element
                    String test = expression.substring(expression.indexOf("("), expression.lastIndexOf(")") + 1);
                    // test - последовательность How и сверху, но с добавлением скобок по краям

                    // т.к. наш метод evaluate() возвращает Double, мы должны преобразовать результат рекрусии в String;
                    String testRecursion = String.valueOf(evaluate(recursion));
                    expression = expression.replace(test, testRecursion);
                    // преобразовали нашу строку с использование рекруси. Избавorсь от первых скобок
                    strList.removeAll(strList);
                    for (String newElement : expression.trim().split(" ")) {
                        strList.add(newElement);
                        strList.add(" ");
                    }
                    // Тут очищаем наш список и сново его заполняем (но уже раскрыв первые скобки)
                }

//                Конструкция 2: первым элиментом, который мы отыскали был  ")"
                String recursion2 = "";
                if (strList.get(i).equals(")")) {

                    for (int j = strList.indexOf("(") + 1; j < strList.indexOf(")"); j++) {
                        recursion2 += strList.get(j);
                    }
                    String test2 = expression.substring(expression.indexOf("("), expression.lastIndexOf(")") + 1);
                    String testRecursion2 = String.valueOf(evaluate(recursion2));
                    expression = expression.replace(test2, testRecursion2);
                    for (String newElement : expression.trim().split(" ")) {
                        strList.add(newElement);
                        strList.add(" ");
                    }
                    // Тут повторor тот же алгоритм, что и в первой конструкции
                }
            }
        }

//  Этап 3
//  Заключительный этап на котором мы будем реализовывать сами вычесления (*/-+)
//  Всю реализацию помещаем в цикл while ( который прекратиться, если все действия будут выполнены (соответственно в списке останется 1 элемент)).
//  Внимательно посмотрите на порядок операций: 1)/ 2)* 3)- 4)+

//        System.out.println(expression + "-------expression-");
//        System.out.println();
        // создаем очередной список для реализации вычеслений, на этот раз без добавления " ".
        List<string> stringList2 = new ArrayList<>();
        for (String element : expression.trim().split(" ")) {
            stringList2.add(element);
        }


        while (stringList2.size() != 0) {
//          работаем со списком: глубоком этапе рекрусии обрабатываем:  (2+0)
//          на среднем: 1 * 1  "or вот этой части уравнения "( ( 2 + 0 ) * 1 ) "
//          Посмтортите сами
//            for (String x : stringList2) System.out.print(x );
//            System.out.println();

            // наш Double :) Также стоит обратить внимание, что для получения класса обертки мы используем не
            // Double.parseDouble() а Double.valueOf()
             Double result = 0d;

//  Сами алгоритмы вычеслений, впринципе понятны, поэтому не буду их комментировать.
//  Однако обратите внимание на очередность, особенно при вычетании (там instead of 1 условия, 3)
//  Если что в комментариях под постом немного объясню, если кто-нибудь дочитает до сюда и у него будет желание)
            if (stringList2.indexOf("/") != -1) {
                int index = stringList2.indexOf("/");
                result = Double.valueOf(stringList2.get(index - 1)) / Double.valueOf(stringList2.get(index + 1));
                stringList2.add(index - 1, String.valueOf(result));
                stringList2.remove(index + 2);
                stringList2.remove(index + 1);
                stringList2.remove(index);
            }
            else if (stringList2.indexOf("*") != -1) {
                int index = stringList2.indexOf("*");
                result = Double.valueOf(stringList2.get(index - 1)) * Double.valueOf(stringList2.get(index + 1));
                stringList2.add(index - 1, String.valueOf(result));
                stringList2.remove(index + 2);
                stringList2.remove(index + 1);
                stringList2.remove(index);
            }
            else if (stringList2.indexOf("-") != -1) {
                int index = stringList2.indexOf("-");
                int lastIndex = stringList2.lastIndexOf("-");
                if (index == 0) {
                    result = 0.0 - Double.valueOf(stringList2.get(index + 1));
                    stringList2.add(0, String.valueOf(result));
                    stringList2.remove(2);
                    stringList2.remove(1);
                }
                else if ((lastIndex-2>0) && (stringList2.get(lastIndex-2).equals("-"))){
                    result = Double.valueOf(stringList2.get(lastIndex + 1)) + Double.valueOf(stringList2.get(lastIndex - 1));
                    stringList2.add(lastIndex - 1, String.valueOf(result));
                    stringList2.remove(lastIndex + 2);
                    stringList2.remove(lastIndex + 1);
                    stringList2.remove(lastIndex);
                }
                else {
                    result = Double.valueOf(stringList2.get(index - 1)) - Double.valueOf(stringList2.get(index + 1));
                    stringList2.add(index - 1, String.valueOf(result));
                    stringList2.remove(index + 2);
                    stringList2.remove(index + 1);
                    stringList2.remove(index);
                }
            }
            else if (stringList2.indexOf("+") != -1) {
                int index = stringList2.indexOf("+");
                result = Double.valueOf(stringList2.get(index - 1)) + Double.valueOf(stringList2.get(index + 1));
                stringList2.add(index - 1, String.valueOf(result));
                stringList2.remove(index + 2);
                stringList2.remove(index + 1);
                stringList2.remove(index);
            }

            // Вот тут все немного коряво. (На всякий случий проверял отсутствие (*/+-))
            if ((stringList2.indexOf("*") == -1) && (stringList2.indexOf("/") == -1) && (stringList2.indexOf("+") == -1) && (stringList2.indexOf("-") == -1)) {
                return result;
            }
        }
        return Double.valueOf(stringList2.get(0));
    }
}
</string></string>
Grazie a tutti coloro che hanno letto e lasciato un commento) Se ci sono commenti, e molto probabilmente ci sono, sarò felice di ascoltarli)
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION