Reputation: 77
I have this example to solve, its quite easy but there is a lots of obstracles:
/**
* Write a JavaScript function to check
* whether it is possible to replace $
* in a given expression x $ y = z
* with one of the four signs +, -, * or /
* to obtain a correct expression.
*/
/**
* If we replace $ in input with one of + - * /
* do we get a valid mathematical expression?
* @param {string} input String that is tested
* @returns {boolean} Whether it could be valid expression
*/
const isReplacable = input => {
/**
* Please fill in your code here
*/
return false;
};
const TEST_STRINGS = [
'3 $ 5 = 8',
'2 $ 6 = 3',
'5$5=25',
'2 $ 1 = 2',
'3 $ 4 = 5',
'6 $ 4 = 3',
'3 $ 2 = 1',
'4 $6= 24',
'3$ 2= 6',
'30$ 15 =2',
];
export const runChecks = () => {
TEST_STRINGS.forEach(expression => {
console.log(`${expression}: ${isReplacable(expression) ? 'VALID' : 'INVALID'}`);
});
};
I tried to finish it like this:
1, make parser
function countIt(test) {
const numbers = test.split('');
const target = ' ';
var i = 0;
while (i < numbers.length) {
if (numbers[i] === target) {
numbers.splice(i, 1);
} else {
++i;
}
}
newNumbers = numbers;
console.log(numbers);
const newTarget = '$';
var i = 0;
while (i < newNumbers.length) {
if (newNumbers[i] === newTarget) {
newNumbers.splice(i, 1);
} else {
++i;
}
}
console.log(newNumbers);
finalNumbers = newNumbers;
const finalTarget = '=';
var i = 0;
while (i < finalNumbers.length) {
if (finalNumbers[i] === finalTarget) {
finalNumbers.splice(i, 1);
} else {
++i;
}
}
console.log(finalNumbers);
if (finalNumbers.length)
firstNumber = finalNumbers[0];
secondNumber = finalNumbers[2];
resultNumber = finalNumbers[4];
const result = parseInt(firstNumber) + parseInt(finalNumbers[1])
if (parseInt(firstNumber) + parseInt(secondNumber ) == resultNumber) {
console.log('+');
}
else if (parseInt(firstNumber) - parseInt(secondNumber ) == resultNumber) {
console.log('-');
}
else if (parseInt(firstNumber) * parseInt(secondNumber ) == resultNumber) {
console.log('*');
}
else if (parseInt(firstNumber) / parseInt(secondNumber ) == resultNumber) {
console.log('/');
}
else {
console.log('false');
}
}
But there is so many problems to solve like 2-digits, or missing white-space after expression so i think my solution it too overenginered and isnt working correctly anyway
Do u have any better solutions ? Thanks for your tips ;)
Upvotes: 1
Views: 133
Reputation: 57
// expression: "number $ number = number"
// left: [number, number]
// right: number
const lexer = (expression) => {
const [left, right] = expression.split('=')
return {
left: left.split('$').map(i => Number(i)),
right: Number(right)
}
}
const calculate = (n1, n2) => {
let r = []
r.push(n1 + n2)
r.push(n1 - n2)
r.push(n1 * n2)
if (n2 !== 0) {
r.push(n1 / n2)
}
return r
}
const isReplacable = (input) => {
const {left, right} = lexer(input)
const cal = calculate.apply(null, left)
return cal.some(i => i === right)
}
The short explanation.
I put the code on https://runkit.com/kennywho/javascript-expression-test
If the expression gets more complex, you can refer to the 24-game and the math expression parser. you can google or find it on Leetcode.
Upvotes: 1
Reputation: 652
let evalBySign = (first, second, answer, sign) => eval(`(${first}) ${sign} (${second})==${answer}`);
let operation = {
'+': function(first, second, answer) {
//Way 1
return Number(first) + Number(second) == answer;
},
'-': function(first, second, answer) {
//Way 2
return eval(`(${first}) - (${second})==${answer}`);
},
'*': function(first, second, answer) {
//Way 2 as function
return evalBySign(first, second, answer, '*');
}
};
['/', '%'].forEach(sign => {
operation[sign] = function(first, second, answer) {
return evalBySign(first, second, answer, sign);
}
});
function isReplacable(input) {
input = input.replace(/\s+/g, '');
let validEq = /\d+\$\d+=\d+/.test(input);
if(!validEq)
return false;
let numbers = input.split(/[\$=]/);
if(numbers.length != 3)
return false;
let [first, second, answer] = numbers;
let operationEntries = Object.entries(operation);
let isReplacelable = false;
for (let entry of operationEntries) {
if(entry[1](first, second, answer)) {
console.log(`${input} equation matched using '${entry[0]}' sign`);
isReplacelable = true;
break;
}
}
return isReplacelable;
}
const TEST_STRINGS = [
'3 $ 5 = 8',
'2 $ 6 = 3',
'5$5=25',
'2 $ 1 = 2',
'3 $ 4 = 5',
'6 $ 4 = 3',
'3 $ 2 = 1',
'4 $6= 24',
'3$ 2= 6',
'30$ 15 =2',
'3 $ = 1 4',
'2 3 5'
];
const runChecks = () => {
TEST_STRINGS.forEach(expression => {
console.log(`${expression}: ${isReplacable(expression) ? 'VALID' : 'INVALID'}`);
});
};
runChecks();
Upvotes: 1
Reputation: 17390
You can do with regex:
Fetch out the three numbers and ignore any whitespaces. If the teststring is in an invalid format (for instance contains invalid characters, no operators, to many or to few numbers, ...) it will return false
immediately, because the regex can't match.
Otherwise just check if any of the four operations on the first two numbers results in the third number ...
const isReplaceable = (input) => {
let match = /^\s*(\d+)\s*\$\s*(\d+)\s*=\s*(\d+)\s*$/.exec(input);
if (!match) return false;
return +match[1] + +match[2] == +match[3] ||
+match[1] - +match[2] == +match[3] ||
+match[1] * +match[2] == +match[3] ||
+match[1] / +match[2] == +match[3]
}
const TEST_STRINGS = [
'3 $ 5 = 8',
'2 $ 6 = 3',
'5$5=25',
'2 $ 1 = 2',
'3 $ 4 = 5',
'6 $ 4 = 3',
'3 $ 2 = 1',
'4 $6= 24',
'3$ 2= 6',
'30$ 15 =2',
];
for (let t of TEST_STRINGS)
console.log(t, isReplaceable(t));
Upvotes: 1
Reputation: 25319
One way to sidestep the whitespace problem would be to (ab)use the fact that parseInt()
is lenient and ignores whitespace. This is of course a hack and not how you should generally write programs, but in this case it makes for a fairly elegant solution.
const isReplaceable = (input) => {
const [a, b, c] = input.split(/\$|=/).map(item => parseInt(item, 10));
return (
a * b === c ||
a / b === c ||
a + b === c ||
a - b === c
);
}
const isReplaceable = (input) => {
const [a, b, c] = input.split(/\$|=/).map(item => parseInt(item, 10));
return (
a * b === c ||
a / b === c ||
a + b === c ||
a - b === c
);
}
const TEST_STRINGS = [
'3 $ 5 = 8',
'2 $ 6 = 3',
'5$5=25',
'2 $ 1 = 2',
'3 $ 4 = 5',
'6 $ 4 = 3',
'3 $ 2 = 1',
'4 $6= 24',
'3$ 2= 6',
'30$ 15 =2',
];
TEST_STRINGS.forEach(item => console.log(isReplaceable(item)));
Upvotes: 3
Reputation: 94
This should probably works
const isReplacable = input => {
/**
* Please fill in your code here
*/
let result = input.split('=')[1].replace(' ','');
let inputs = input.split('$');
let input1 = inputs[0].replace(' ','');
let input2 = inputs[1].replace(' ','');
if(Number(input1) + Number(input2) == Number(result)) {
// its sum, do things
} else if(Number(input1) - Number(input2) == Number(result)) {
// decrement
} else if(Number(input1) / Number(input2) == Number(result)) {
// division
} else if(Number(input1) * Number(input2) == Number(result)) {
// multiply
} else {
// wrong input
}
return false;
};
I hope you got it.
Upvotes: 0