So, I've searched high and low, and I can't find an answer to this. I've attempted it about three times and gotten a basic one cranked out by basically storing the input in an array as a string, parsing the numbers, then switching on the operator, in order to evaluate the integers, but I'm having a really hard time figuring out the chaining logic. Does anyone have any suggestions? Of maybe even just the psuedocode? I really don't want to use eval. Thanks a lot
For a simple calculator with only 5 operators (^, *, /, +, -) and no parentheses, you can do something like this. First, it is convenient to turn the string into an array of numbers and operators. Then, we go through the array looking for each operator in order of precedence, and applying the operator to the numbers preceding and following the it.
function tokenize(s) {
// --- Parse a calculation string into an array of numbers and operators
const r = [];
let token = '';
for (const character of s) {
if ('^*/+-'.includes(character)) {
if (token === '' && character === '-') {
token = '-';
} else {
r.push(parseFloat(token), character);
token = '';
}
} else {
token += character;
}
}
if (token !== '') {
r.push(parseFloat(token));
}
return r;
}
function calculate(tokens) {
// --- Perform a calculation expressed as an array of operators and numbers
const operatorPrecedence = [{'^': (a, b) => Math.pow(a, b)},
{'*': (a, b) => a * b, '/': (a, b) => a / b},
{'+': (a, b) => a + b, '-': (a, b) => a - b}];
let operator;
for (const operators of operatorPrecedence) {
const newTokens = [];
for (const token of tokens) {
if (token in operators) {
operator = operators[token];
} else if (operator) {
newTokens[newTokens.length - 1] =
operator(newTokens[newTokens.length - 1], token);
operator = null;
} else {
newTokens.push(token);
}
}
tokens = newTokens;
}
if (tokens.length > 1) {
console.log('Error: unable to resolve calculation');
return tokens;
} else {
return tokens[0];
}
}
const userInput = document.getElementById('userInput');
userInput.focus();
userInput.addEventListener('input', function() {
document.getElementById('result').innerHTML = "The answer is " + calculate(tokenize(userInput.value));
});
<input type="text" id="userInput" />
<div id="result"></div>
(Alternative version here). To allow parentheses, you could tell the calculate function to check for parentheses before it starts looking for any of the other operators, then recursively call itself on the expression within each set of parentheses. The parsing function can also be improved e.g. removing any white space and dealing with errors.
Related
I am not sure if 'variable' is the correct word to use here but essentially, I would like to create a variable operator using JavaScript.
So far, the best thing I can think of is to create a switch statement but it seems very repetitive and tedious to do. Is there any way I can write one "If Statement" with a conditional operator?
What I have thought of:
variableOperator(x, y, operator) {
switch(operator) {
case '>=':
if (x >= y) {
// logic
}
break;
case '<=':
if (x <= y) {
// logic
}
break;
case '<':
if (x < y) {
// logic
}
break;
case '<':
if (x < y) {
// logic
}
break;
}
}
What I am wondering if is possible in pseudo-code (code below will obviously not work but in concept, this is what ideally I would like to use). No matter what the operator is (greater than, equals to, etc.) this if statement can take care of it:
variableOperator(x, y, operator) {
if (x operator y) {
// logic
}
}
Edit: I should have clarified: x and y don't always have to be number types.
Mainly, I'm wondering about string (a-z,A-Z,0-9) comparison (== or !=) and number comparison (<, >, <=, >=). The project I'm working on does not need to worry about emoji's or other complex characters.
In essence, regardless of whether I'm comparing strings or numbers, I'm wondering if the operator itself can be a variable that can be easily manipulated/changed so that one would't have to write a separate bit of code for each case.
Encode your operators in a lookup table and then you can use that in order to determine what to do. This reduces your code to just an if statement to check if the values pass the operator check. You can also include a fallback - if the operator is not found, just assume it fails.
const operators = {
">" : (a, b) => a > b ,
">=": (a, b) => a >= b,
"<" : (a, b) => a < b ,
"<=": (a, b) => a <= b,
"==": (a, b) => a == b,
}
function doStuff(x, y, op) {
const check = operators[op] ?? (() => false);
if (check(x, y)) {
console.log("do something");
} else {
console.log("ignore");
}
}
doStuff(4, 2, ">");
doStuff(2, 4, "<");
doStuff("apple", "banana", "<");
doStuff(4, 2, "==");
doStuff(4, 2, "👎");
The problem wants me to output the string "Edabit" with the number of "a" characters equaling the initial number passed through the function.
I have tried different methods of concatenation but for some reason the string of "a"s seem to ignore their place in the concatenation.
function howManyTimes(num) {
let str = ''
if (num === 0){
return `Ed${str}bit`
}
else {
str += 'a'
return str += howManyTimes(num - 1)
}
}
console.assert(howManyTimes(0) == "Edbit", "1. Instead got "+howManyTimes(0));
console.assert(howManyTimes(1) == "Edabit", "2. Instead got "+howManyTimes(1));
console.assert(howManyTimes(10) == "Edaaaaaaaaaabit", "3. Instead got "+howManyTimes(10));
function howManyTimes(num, str) {
if (!str) str = '';
if (num > 0) {
return howManyTimes(num - 1, str + 'a');
} else {
return `Ed${str}bit`;
}
}
console.log(howManyTimes(8));
One issue is that your recursion is always appending the result of the method to an a. Rather than doing that, pass along the aggregated string to then be used once you reach the end.
You can always separate out the part that can use straightforward recursion from a shell that calls that part and does something with the result. For instance,
const nAs = (n) =>
n == 0 ? '' : nAs (n - 1) + 'a'
const howManyTimes = (n) =>
`Ed${nAs (n)}bit`
console .log (howManyTimes (0))
console .log (howManyTimes (1))
console .log (howManyTimes (10))
Of course I would only write it this way in a recursion challenge. For this example, there are more straightforward ways to write this, including const howManyTimes = (n) => `Ed${'a'.repeat(n)}bit`
How can I achieve that users can add multiply custom if-statements?
For example let's say there is a given variable called x with a given value of let's say 8.
The user sees that x = 8 and has a button to add an if-statement. He clicks the button and can insert the condition which triggers an event (let's say it prints "Hello World"). So he enters "x < 100" into the field which is true. Therefore "Hello World" is printed.
After clicking the button once again, he is able to add an other condition, let's say "x < 7" which is also true. Because both conditions are true, "Hello World" is still printed.
I think you got the point of my questions, even though I lack the vocabulary.
So how could I manage to let user add an undefined amount of conditions which will be checked before "Hello World" is printed?
The only solution I know is to limit the possible amount of conditions and check each one if it is empty / what the conditions says.
Thanks a lot!
Unless you want to build an entire language you have to get clear on what exact operations you are going to allow here.
For example the operation of < and > and ==, basically all comparison operations (<= and >= as well) can be implemented via the following:
/* your X variable, might be var if you desire to change */
let x = 12
/* the array of conditions the user entered */
var conditions : [(((Int, Int) -> Bool), Int)] = []
/* some user input - read as e.g. "x > 2"*/
conditions.append((<, 100))
conditions.append((>, 2))
conditions.append((==, 12))
/* you evaluate all conditions in the following way */
let eval = conditions.map { $0(x, $1) }
let allTrue = !eval.contains(false)
/* allTrue would be true in this case because 12 < 100 && 12 > 2 && 12 == 12 */
Your "hard" job is it now to interpret the user input as some condition. But that is not too difficult, you simply need a mapping of the text input of "<" to the actual operator <.
You can adjust the above code to take care of Double instead of Int easily if you fell like you need that. But you have to aware of floating point inaccuracy and the problem that arise when checking for equality (thanks to #dfri for pointing this out).
A little bit more difficult part comes in regards to combining the conditions with or instead of and what above code does and what you currently describe in your question.
Just because I like closures: The following is the entire input reading and parsing:
func getOperator(str: String) -> ((Int, Int) -> Bool)? {
switch str {
case "<":
return (<)
case ">":
return (>)
case "==":
return (==)
case "<=":
return (<=)
case ">=":
return (>=)
default:
return nil
}
}
func parseUserInput(str:String) -> (((Int, Int) -> Bool), Int) {
var input = str as NSString
input = input.stringByReplacingOccurrencesOfString(" ", withString: "")
//let variable = input.substringToIndex(1) // in case you want more than one variable, but that will have to change the entire setup a bit
// this has to be this "ugly" to incorporate both 1 char and 2 char long operators
let operato = input.substringFromIndex(1).stringByTrimmingCharactersInSet(NSCharacterSet.alphanumericCharacterSet())
let number = input.substringFromIndex(operato.lengthOfBytesUsingEncoding(NSASCIIStringEncoding) + 1)
if let number = Int(number), op = getOperator(operato) {
return (op, number)
}
return ((<, 999999)) // need some error handling here
}
conditions.append(parseUserInput("x > 123"))
Instead of resolving the operator using a function you can even use a plain old dictionary mapping from ">" to (>) etc.
First you need a way to switch between operators. A very simple enum is perfect for this. Just add all the operators you want to use.
enum Operator : String {
case biggerThan = ">"
case smallerThan = "<"
case equal = "=="
init?(string:String) {
switch string {
case ">" :
self = .biggerThan
case "<" :
self = .smallerThan
case "==" :
self = .equal
default :
return nil
}
}
}
Each time a user clicks a button and inserts a condition, a corresponding Condition value will be created.
struct Condition {
var value: Int
var operation: Operator
}
This function returns a Bool depending on x, the inputValue and the chosen operator.
func checkCondition(x: Int, condition: Condition) -> Bool {
switch condition.operation {
case .biggerThan :
return condition.value > x
case .smallerThan :
return condition.value < x
case .equal :
return condition.value == x
}
}
This does the same but for a whole bunch of conditions. Here you can implement more logic. If all need to be true for example add : if !result { return false }.
func checkAllConditions(x:Int, conditions: [Condition]) {
for condition in conditions {
let result = checkCondition(x, condition: condition)
print(result)
}
}
Now all you need to do is store conditions in an array as the user creates them
func userCondition(operation:String, input:String) -> Condition? {
guard let op = Operator(string: operation) else {
return nil
}
guard let doubleValue = Double(input) else {
return nil
}
return Condition(value: Int(doubleValue), operation: op)
}
let conditionA = userCondition("<", input: "10")! // use if let instead of !
let conditionB = userCondition(">", input: "10")! // use if let instead of !
let conditionC = userCondition("==", input: "23")! // use if let instead of !
var x : Int = 23
checkAllConditions(x, conditions: [conditionA,conditionB,conditionC])
struct MyConditions {
let myEps: Double = 0.001
var x: Double
var lessThan = [Double]()
var equalTo = [Double]()
var greaterThan = [Double]()
init(x: Double) {
self.x = x
}
mutating func addConstraint(operand: Double, op: String) {
if op == "<" {
lessThan.append(operand)
}
else if op == "==" {
equalTo.append(operand)
}
else if op == ">" {
greaterThan.append(operand)
}
}
func checkConstraints() -> Bool {
for op in lessThan {
if !(x < op) {
return false
}
}
for op in equalTo {
if !(x - myEps < op && x + myEps > op) {
return false
}
}
for op in greaterThan {
if !(x > op) {
return false
}
}
return true
}
}
Tests:
func feasibleHelloWorld(x: MyConditions) {
if x.checkConstraints() {
print("Hello world!")
}
}
var x = MyConditions(x: 8)
x.addConstraint(100, op: "<")
x.checkConstraints() // true
feasibleHelloWorld(x) // Hello world!
x.addConstraint(8, op: "==")
x.checkConstraints() // true
feasibleHelloWorld(x) // Hello world!
x.addConstraint(7, op: "<")
x.checkConstraints() // false
feasibleHelloWorld(x) // ... nothing
I would like to create a simple filtering language in Javascript.
I want to search inside a collection of products, say:
product=[
{price:10,name:"T-Shirt",category:"Clothing",published_at:"07-08-2014",size:"10x30",color:"#0000FF"},
{price:20,name:"Chair",category:"Furniture",published_at:"09-03-2013",size:"30x30",color:"#00FF00"},
{price:30,name:"iPhone",category:"Phones",published_at:"17-03-2014",size:"40x30",color:"#FF00FF"},
{price:40,name:"Samsung Galaxy",category:"Phones",published_at:"12-01-2012",size:"10x60",color:"#00BBBB"},
];
With only one input of text, I would like to be able to query inside this array, for example:
cat:Clothing => gives back the tshirt
price:>15 => gives back Chair, iPhone, and Samsung Galaxy
name:iP => Filters trough the names and gives back iPhone
price:>15&&size:>35x25 => Filters trough the names and gives back iPhone
I know they are some language parsers like
https://github.com/tolmasky/language
https://github.com/zaach/jison (used by coffeescript)
but I don't know which one to choose (and why) and if it is a good idea to use one ? Any ideas ?
I think this is simple enough to do yourself without a library.
Here's my crack at it:
http://jsfiddle.net/qrz48/2/
// polyfill Array.prototype.forEach if you need to support older browsers...
// there's one at: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
var product = [
{price:10,name:"T-Shirt",category:"Clothing",published_at:"07-08-2014",size:"10x30",color:"#0000FF"},
{price:20,name:"Chair",category:"Furniture",published_at:"09-03-2013",size:"30x30",color:"#00FF00"},
{price:30,name:"iPhone",category:"Phones",published_at:"17-03-2014",size:"40x30",color:"#FF00FF"},
{price:40,name:"Samsung Galaxy",category:"Phones",published_at:"12-01-2012",size:"10x60",color:"#00BBBB"}
];
// extend this as you require new search operators.
var operators = {
"==": function(a, b) {return a == b;},
"===": function(a, b) {return a === b;},
">": function(a, b) {return a > b;},
">=": function(a, b) {return a >= b;},
"<": function(a, b) {return a < b;},
"<=": function(a, b) {return a <= b;},
"*": function(a, b) {return a.indexOf(b) > -1;}
};
// usage: find("category", "===", "Clothing")
function find(key, operator, condition, searchIn) {
if( ! searchIn) {
searchIn = product;
}
var result = [];
searchIn.forEach(function(item) {
if(operators[operator](item[key], condition)) {
result.push(item);
}
});
return result;
}
// usage: query("category:===:Clothing");
function query(str) {
var conditions = str.split("&&");
var result = [];
conditions.forEach(function(condition, index) {
var parts = condition.split(":");
var key = parts[0];
var operator = parts[1];
var condition = parts[2];
var searchIn = (conditions.length > 1 && index > 0) ? result : null;
result = find(key, operator, condition, searchIn);
});
return result;
}
// usage
console.log(query("category:===:Clothing"));
console.log(query("price:>:20"));
console.log(query("name:*:iP"));
console.log(query("price:>:20&&name:*:Galaxy"));
You can pass a search string to the query function above, as requested, with the exception that a colon is required both before and after the condition operator. For example, to find all products where the price is greater than 20, run:
query("price:>:20");
You can also combine search conditions using the format in your question:
query("price:>:20&&category:===:Clothing");
I couldn't think how to do your size comparison without splitting the size data out into separate values, e.g. sizeX and sizeY, which would be easier to compare using something like
query("sizeX:>:30&&sizeY:>:20");
If anything this was just quite fun to write. What do you think?
I have decided to test with JISON (Similar to BISON)
/* description: Parses end executes mathematical expressions. */
/* lexical grammar */
%lex
%%
\s+ /* skip whitespace */
[0-9]+("."[0-9]+)?\b return 'NUMBER'
">" return '>'
"price:" return 'PRICE'
<<EOF>> return 'EOF'
"name:" return 'NAME'
[a-z]+ return 'STRING'
"," return 'COMMA'
/lex
/* operator associations and precedence */
%left 'COMMA'
%left 'PRICE' 'NAME'
%start expressions
%% /* language grammar */
expressions
: e EOF
{ typeof console !== 'undefined' ? console.log($1) : print($1);
return $1; }
;
e
: 'PRICE' '>' e
{$$ = {price:{gt:$3}};}
| 'NAME' e
{$$ = {name:{contains:$2}};}
| NUMBER
{$$ = Number(yytext);}
| STRING
{$$ = String(yytext);}
| e 'COMMA' e
{ for (var attrname in $1) { $3[attrname]=$1[attrname]; $$ = $3; }}
;
The result of the parser is the following:
price:>30 => { price: { gt: 30 } }
name:blabla,price:>10 => { price: { gt: 10 }, name: { contains: 'blabla' } }
name:test => { name: { contains: 'test' } }
This solution seems a bit more portable to me, because it doesn't directly deal with the parsing.
I've been working on implementing the Shunting-Yard Algorithm in JavaScript for class.
Here is my work so far:
var userInput = prompt("Enter in a mathematical expression:");
var postFix = InfixToPostfix(userInput);
var result = EvaluateExpression(postFix);
document.write("Infix: " + userInput + "<br/>");
document.write("Postfix (RPN): " + postFix + "<br/>");
document.write("Result: " + result + "<br/>");
function EvaluateExpression(expression)
{
var tokens = expression.split(/([0-9]+|[*+-\/()])/);
var evalStack = [];
while (tokens.length != 0)
{
var currentToken = tokens.shift();
if (isNumber(currentToken))
{
evalStack.push(currentToken);
}
else if (isOperator(currentToken))
{
var operand1 = evalStack.pop();
var operand2 = evalStack.pop();
var result = PerformOperation(parseInt(operand1), parseInt(operand2), currentToken);
evalStack.push(result);
}
}
return evalStack.pop();
}
function PerformOperation(operand1, operand2, operator)
{
switch(operator)
{
case '+':
return operand1 + operand2;
case '-':
return operand1 - operand2;
case '*':
return operand1 * operand2;
case '/':
return operand1 / operand2;
default:
return;
}
}
function InfixToPostfix(expression)
{
var tokens = expression.split(/([0-9]+|[*+-\/()])/);
var outputQueue = [];
var operatorStack = [];
while (tokens.length != 0)
{
var currentToken = tokens.shift();
if (isNumber(currentToken))
{
outputQueue.push(currentToken);
}
else if (isOperator(currentToken))
{
while ((getAssociativity(currentToken) == 'left' &&
getPrecedence(currentToken) <= getPrecedence(operatorStack[operatorStack.length-1])) ||
(getAssociativity(currentToken) == 'right' &&
getPrecedence(currentToken) < getPrecedence(operatorStack[operatorStack.length-1])))
{
outputQueue.push(operatorStack.pop())
}
operatorStack.push(currentToken);
}
else if (currentToken == '(')
{
operatorStack.push(currentToken);
}
else if (currentToken == ')')
{
while (operatorStack[operatorStack.length-1] != '(')
{
if (operatorStack.length == 0)
throw("Parenthesis balancing error! Shame on you!");
outputQueue.push(operatorStack.pop());
}
operatorStack.pop();
}
}
while (operatorStack.length != 0)
{
if (!operatorStack[operatorStack.length-1].match(/([()])/))
outputQueue.push(operatorStack.pop());
else
throw("Parenthesis balancing error! Shame on you!");
}
return outputQueue.join(" ");
}
function isOperator(token)
{
if (!token.match(/([*+-\/])/))
return false;
else
return true;
}
function isNumber(token)
{
if (!token.match(/([0-9]+)/))
return false;
else
return true;
}
function getPrecedence(token)
{
switch (token)
{
case '^':
return 9;
case '*':
case '/':
case '%':
return 8;
case '+':
case '-':
return 6;
default:
return -1;
}
}
function getAssociativity(token)
{
switch(token)
{
case '+':
case '-':
case '*':
case '/':
return 'left';
case '^':
return 'right';
}
}
It works fine so far. If I give it:
((5+3) * 8)
It will output:
Infix: ((5+3) * 8)
Postfix (RPN): 5 3 + 8 *
Result: 64
However, I'm struggling with implementing the unary operators so I could do something like:
((-5+3) * 8)
What would be the best way to implement unary operators (negation, etc)? Also, does anyone have any suggestions for handling floating point numbers as well?
One last thing, if anyone sees me doing anything weird in JavaScript let me know. This is my first JavaScript program and I'm not used to it yet.
The easiest thing would be to make isNumber match /-?[0-9]+(\.[0-9]+)?/, handling both floating points and negative numbers.
If you really need to handle unary operators (say, unary negation of parenthesized expressions), then you have to:
Make them right-associative.
Make them higher precedence than any of the infix operators.
Handle them separately in EvaluateExpression (make a separate PerformUnaryExpression function which only takes one operand).
Distinguish between unary and binary minus in InfixToPostfix by keeping track of some kind of state. See how '-' is turned into '-u' in this Python example.
I wrote up a more thorough explanation of handling unary minus on another SO question.
my suggestion is this. don't handle the '-' as an arithmetic operator. treat it as a 'sign' operator. or treat it as if it's a part of the whole operand (i.e. its sign). what i mean is that everytime you encounter '-', you just have to multiply the operand after it by -1, then proceed to read the next token. :) i hope that helps. just a simple thought...
I could solve this problem by modifying unary operators('+' and '-') to distinguish them from the binary ones.
For example, I called the unary minus 'm' and unary plus 'p', making them right-assocative and their precedence equal to the exponent operator('^').
To detect if the operator is unary I simply had to check if the token before the operator was an operator or an opening bracket.
This is my implementation in C++:
if (isOperator(*token))
{
if (!isdigit(*(token - 1)) && *(token - 1) != ')') // Unary check
{
if (*token == '+')
*token = 'p'; // To distinguish from the binary ones
else if (*token == '-')
*token = 'm';
else
throw;
}
short prec = precedence(*token);
bool rightAssociative = (*token == '^' || *token == 'm' || *token == 'p');
if (!operators.empty())
{
while (prec < precedence(operators.top()) || (prec == precedence(operators.top()) && !rightAssociative))
{
rpn += operators.top();
operators.pop();
if (operators.empty())
break;
}
}
operators.push(*token);
}
Here operators is a stack and token is an iterator to the infix expression string
(This just the operator handling part)
When I needed to support this, I did this in an intermediate stage. I started by generating a list of all expression lexemes, then used helper functions to extract operators and operands and the "get operand" function simply consumed two lexemes whenever it saw a unary operator.
It really helps if you use another character to signify "unary minus", though.
In my Java implementation I did it in next way:
expression = expression.replace(" ", "").replace("(-", "(0-")
.replace(",-", ",0-");
if (expression.charAt(0) == '-') {
expression = "0" + expression;
}
To handle floating point numbers you can change your (number part of) regex to:
/([0-9]+\.?[0-9]*)/
so the final regex would be:
/([0-9]+\.?[0-9]*|[*+-\/()])/
And for handling unary minus operator, you can change it to another character like 'u'.
(As it is explained here by -TGO)
The javascript code that i wrote for handling unary minus operator based on the link given is:
// expr is the given infix expression from which, all the white spaces has been
// removed.(trailing and leading and in between white space characters)
const operators = ['+', '*', '-', '/', '^'];
const openingBrackets = ['(', '[', '{'];
let exprArr = Array.from(expr);
// Since strings are immutable in js, I am converting it to an array for changing
// unary minus to 'u'
for (let i = 0; i < expr.length; i++) {
if (expr[i] === '-') {
if (i === 0) {
exprArr[i] = 'u';
} else if (operators.includes(expr[i - 1])) {
exprArr[i] = 'u';
} else if (openingBrackets.includes(expr[i - 1])) {
exprArr[i] = 'u';
} else {
// '-' is not a unary operator
// it is a binary operator or we have the wrong expression, so...
if (!openingBrackets.includes(expr[i + 1]) && !/[0-9]/.test(expr[i + 1])) {
throw new Error("Invalid Expression...");
}
}
}
}
// And finally converting back to a string.
let expr2 = exprArr.join('');
This isn't in Javascript, but here is a library I wrote to specifically solve this problem after searching and not finding any clear answers.
This does all you want and more:
https://marginalhacks.com/Hacks/libExpr.rb/
It is a ruby library (as well as a testbench to check it) that runs a modified shunting yard algorithm that also supports unary ('-a') and ternary ('a?b:c') ops. It also does RPN, Prefix and AST (abstract syntax trees) - your choice, and can evaluate the expression, including the ability to yield to a block (a lambda of sorts) that can handle any variable evaluation. Only AST does the full set of operations, including the ability to handle short-circuit operations (such as '||' and '?:' and so on), but RPN does support unary. It also has a flexible precedence model that includes presets for precedence as done by C expressions or by Ruby expressions (not the same). The testbench itself is interesting as it can create random expressions which it can then eval() and also run through libExpr to compare results.
It's fairly documented/commented, so it shouldn't be too hard to convert the ideas to Javascript or some other language.
The basic idea as far as unary operators is that you can recognize them based on the previous token. If the previous token is either an operator or a left-paren, then the "unary-possible" operators (+ and -) are just unary and can be pushed with only one operand. It's important that your RPN stack distinguishes between the unary operator and the binary operator so it knows what to do on evaluation.