CodeWars에서의 나의 모험에 관한 또 다른 기사입니다. 이를 위해 기본 계산기의 기능을 구현합니다. 연산자 문자열(), +, -, *, /가 제공되는 간단한 계산기를 만듭니다 . 내 벨트에는 10개 이상의 JavaRush 레벨만 있으므로 코드가 상당히 번거롭지만 완벽하게 작동합니다. 아시다시피 이 작업은 CodeWars 웹사이트에서 가져온 것입니다 . 그녀의 순위는 3급 이다 . 비공개 메시지로 링크를 알려드릴 수 있습니다. 다음은 나에게 도움이 된 방법 및 프로세스의 일부 목록입니다.
- 재귀. 이 경우 괄호를 없애기 위해서는 메소드가 자신을 호출하는(처음 사용하는 경우 :)) 과정이 필요합니다.
- 메소드
String
'atrim()
,split()
,substring()
,replace()
. - 기본 수집 방법
List
. - 유형 변환도 가능
Double
합니다String
.
* > / > + > -
만 예를 들어 이 옵션을 사용하면 12/6 * 32/2
프로그램이 먼저 곱셈( 6*32
)을 수행하고 모든 것이 내리막길로 진행된다는 것을 깨달았습니다. 그래서 순서는 다음과 같이 되었습니다: * > / > + > -
. 몇 시간 더 지나서 나는 가장 큰 조약돌을 발견했습니다 -
. 다양한 위치와 다양한 조합으로 그는 모든 것을 변화시켰습니다 . (물론 이것은 내 잘못입니다. 예를 들어 , -34
목록의 한 셀이 아니라 두 셀에 있습니다. 하나는 -
다른 하나는 34
). 이 때문에 우리는 를 사용하여 계산에 2개의 추가 논리를 작성해야 했습니다 -
. 일반적으로 코드에서 이를 볼 수 있습니다. 코드에 불필요한 코멘트를 한 점 사과드리며, 제 생각의 흐름을 최대한 공개하고 거기에서 무슨 일이 일어나고 있는지 설명하고 싶었습니다.
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>
읽고 댓글을 남겨주신 모든 분들께 감사드립니다.) 댓글이 있거나 있을 가능성이 높으면 기꺼이 듣겠습니다.)
내 이전 기사: |
---|
GO TO FULL VERSION