Skip to content

Instantly share code, notes, and snippets.

@eternal44
Last active May 20, 2016 07:04
Show Gist options
  • Save eternal44/287ee6c6cd1b02716d89462b234f3b01 to your computer and use it in GitHub Desktop.
Save eternal44/287ee6c6cd1b02716d89462b234f3b01 to your computer and use it in GitHub Desktop.
Calculate a stringified math equation
function evaluate(string){
// reverse string & evaluate backwards to keep indexes relevant
console.log('original string: ', string);
string = reverseString(string);
var opArr = [];
var singleExp;
var firstPart;
var secondPart;
var evalString;
var strLength = string.length;
// evaluate backwards
for(var i = strLength - 1; i >= 0; i--){
singleExp = findOpIndex(string[i]);;
if(singleExp){
singleExp.opIndex = i;
opArr.push(singleExp);
}
if(opArr.length === 2){
if(opArr[0].priority >= opArr[1].priority){
firstPart = string.slice(opArr[1].opIndex + 1)
secondPart = string.slice(0, opArr[1].opIndex + 1)
evalString = calculateBase(firstPart);
string = secondPart + evalString;
opArr.shift();
}
else {
firstPart = string.slice(opArr[0].opIndex)
secondPart = string.slice(0, opArr[0].opIndex)
evalString = calculateBase(secondPart);
string = evalString + firstPart;
opArr.pop();
}
}
}
return findOpIndex(string) ? calculateBase(string) : string;
}
function findOpIndex (string){
var opMap = string.match(/[+-\/*]/);
if (!opMap) return null;
if(opMap[0] === '*' || opMap[0] === '/'){
priority = true;
} else {
priority = false;
}
return {
op: opMap[0],
opIndex: opMap.index,
priority: priority
};
}
function calculateBase(string){
var opMap = findOpIndex(string);
var opIndex = opMap.opIndex;
var op = opMap.op;
var leftNum = string.slice(0, opIndex).trim();
var rightNum = string.slice(opIndex + 1).trim();
return singleOperator(leftNum, rightNum, op)
}
// calculating numbers in reverse since we're evaluating numbers in reverse
function singleOperator (num1, num2, operator){
if(operator === '+') return parseInt(num2) + parseInt(num1);
if(operator === '-') return num2 - num1;
if(operator === '*') return num2 * num1;
if(operator === '/') return num2 / num1;
}
function reverseString(string){
var strArray = string.split(/([*/+-/(/)])/);
var temp;
var currentChar;
var strLength = strArray.length
for (var i = 0; i < strLength / 2; i++){
currentChar = strArray[i];
if(strArray[i] === '(') {
strArray[i] = ')';
} else if(strArray[i] === ')') {
strArray[i] = '(';
} else if(strArray[strLength - i] === ')') {
strArray[strLength - i] = '(';
} else if(strArray[strLength - i] === '(') {
strArray[strLength - i] = ')';
}
temp = strArray[i];
strArray[i] = strArray[strLength - i]
strArray[strLength - i] = temp;
}
return strArray.join('');
}
function evalParens(string) {
string = reverseString(string);
// using a subroutine so we don't reverse the string on each recursion
function subroutine(str){
console.log('input str:', str);
var parensArr = [];
var start;
var end;
for (var i = str.length - 1; i >= 0; i--){
if(str[i] === ')') {
if(parensArr.length === 0) {
start = i;
}
parensArr.unshift(str[i])
} else if (str[i] === '(') {
parensArr.shift()
if(parensArr.length === 0) {
end = i;
console.log('points', str.slice(end + 1, start))
// evaluate paren-less expression and replace it with the result...
subroutine(str.slice(end + 1, start))
}
}
}
str = evaluate(str);
console.log('end str: ', str)
}
return subroutine(string);
}
console.log(evaluate('3 + 4*6'))// 27
// console.log(evalParens('(4 + 2) * 1 + 4+9/2 + (4-3*(3 + (4*3)))'))// 27
// console.log(evaluate("1+3*2*3"))//19
// console.log(evaluate("3*2*3+1"))//19
// console.log(evaluate('2 + 3 - 2 + 33 - 3 + 55'))// 88
// console.log(evaluate("3*2+1*3"))// 9
// console.log(evaluate("3*2*3"))//18
// console.log(evaluate("2 + 5 + 1")); // 8
// console.log(evaluate("-2 * 5")); // 10
// console.log(evaluate("203112 + 5")); 203117
// console.log(evaluate("3*2*4+1*3"))//27
// console.log(evaluate("3+2+8*2/3")) // 10.333333...
// console.log(evaluate("2*1+1+6/3"))//5
// console.log(evaluate("2+5+3"));
// console.log(evaluate("2+5-3"));//4
// console.log(evaluate("123+6")); // 129
// console.log(evalParens("(123+6) * 2"));// 258
// console.log(evalParens("6 / (1 + 2 ) + 14 * ((5 - 2) * 0)"));
/*
##########
# PROMPT #
##########
A function that accepts an expression string (e.g. "1+6/3-2*8") and returns a numerical result (e.g. -13)
The expression string will contain only numbers (1 or more digits each) and operators (+, -, /, *)
Bonus points: write a function to evaluate expressions that may contain parentheses
###############
# ASSUMPTIONS #
###############
- we will only receive clean inputs:
- no dividing by zero, trailing operators, or spaces between strings
- rounding to the closest whole number
#########
# NOTES #
#########
I first attempted to solve this problem recursively and got stuck so I started over with
simple iterators.
########
# TODO #
########
- try again with recursion
- refactor repeated code and hard coded values
- handle spaces in string
*/
var calculate = function(str){
var stringArray = str.split('')
var calculatedValue;
while(stringArray.length !== 1){
for (var i = 0; i < stringArray.length - 1; i++){
if(stringArray[i] === '/' || stringArray[i] === '*'){
calculatedValue = singleOperator(stringArray[i - 1], stringArray[i + 1], stringArray[i])
stringArray.splice(i - 1, 3, calculatedValue)
i = 0
}
}
for (var i = 0; i < stringArray.length - 1; i++){
if(stringArray[i] === '-' || stringArray[i] === '+'){
calculatedValue = singleOperator(stringArray[i - 1], stringArray[i + 1], stringArray[i])
stringArray.splice(i - 1, 3, calculatedValue)
}
}
}
// returns a number rounded to the closest whole number
return Math.round(parseInt(stringArray[0]));
}
var singleOperator = function(num1, num2, operator){
if(operator === '-'){
return num1 - num2;
}
if(operator === '+'){
return parseInt(num1) + parseInt(num2);
}
if(operator === '*'){
return num1 * num2;
}
if(operator === '/'){
return num1 / num2;
}
}
console.log(calculate("3*2*4+1*3"))//27
console.log(calculate("3+2+8*2/3")) // fix
console.log(calculate("2*1+1+6/3"))/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment