CodeWars-dakı sərgüzəştlərim haqqında başqa bir məqalə. Bunun üçün elementar kalkulyatorun funksionallığını həyata keçiririk: (), +, -, *, / operatorlar sətirini verən sadə kalkulyator yaradın . Mənim kəmərim altında cəmi 10+ JavaRush səviyyəsi var, ona görə də kod olduqca çətin, lakin mükəmməl işləyir. Gördüyünüz kimi, tapşırıq CodeWars veb saytındandır . Onun dərəcəsi 3kyu-dur . Linki şəxsi mesajda verə bilərəm. Budur mənə kömək edən üsul və proseslərin qismən siyahısı:
- Rekursiya. Metodun özünü çağırdığı proses (ilk dəfə istifadə :)) bu halda mötərizələrdən xilas olmaq üçün lazımdır.
- Metodlar
String
'atrim()
,split()
,substring()
,replace()
. - Əsas toplama üsulları
List
. - Eləcə də növə
Double
vəString
növbəyə çevrilmə.
* > / > + > -
, amma başa düşdüm ki, məsələn, bu seçimlə: 12/6 * 32/2
, proqram əvvəlcə vurma ( 6*32
) yerinə yetirəcək və hər şey aşağı enəcək, beləliklə sifariş belə oldu: * > / > + > -
. Daha bir neçə saatdan sonra ən böyük çınqıl daşına rast gəldim - -
. Fərqli mövqelərdə və fərqli kombinasiyalarda HƏR ŞEYİ dəyişdi . (Bu, əlbəttə ki, mənim günahımdır, çünki, məsələn: -34
, siyahının bir xanasında deyil, ikisində yerləşir: birində, -
digərində, 34
). Buna görə ilə hesablamalarda əlavə 2 məntiq yazmalı olduq -
, ümumiyyətlə kodda bunu görəcəksiniz. Koddakı lazımsız şərhlərə görə üzr istəyirəm, düşüncə qatarımı mümkün qədər ortaya qoymaq və orada baş verənləri izah etmək istədim.
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>
Oxuyan və şərh yazan hər kəsə təşəkkürlər) Əgər şərhlər varsa və çox güman ki, var, onları eşitməyə şad olaram)
Əvvəlki məqalələrim: |
---|
GO TO FULL VERSION