Last active
May 20, 2016 07:04
-
-
Save eternal44/287ee6c6cd1b02716d89462b234f3b01 to your computer and use it in GitHub Desktop.
Calculate a stringified math equation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)")); | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
########## | |
# 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