I have this Rational class that has a method for each operation (add,mult etc)
function Rational(nominator, denominator){
this.nominator = nominator;
this.denominator = denominator || 1;
}
Rational.prototype = {
mult: function(that) {
return new Rational(
this.nominator * that.nominator,
this.denominator * that.denominator
);
},
print: function() {
return this.nominator + '/' + this.denominator;
}
};
var a = new Rational(1,2),
b = new Rational(3);
console.log( a.mult(b).print() ); // 3/2
Can I make it more "natural" e.g. to enable console.log( a * b ) ?
You can't overload operators (read similar questions).
Moreover, a dedicated method like mult can be treated as a sign of good design (not only in Javascript), since changing the original operator behavior can confuse users (well, a rational number actually a good candidate for overloading).
You can change print to toString as user thg435 has suggested.
Going even further:
Rational.prototype = {
mult : ... ,
toString: ... ,
valueOf: function() { return this.nominator / this.denominator; }
};
this will enable the a * b syntax (note: you don't operate on Rationals any more, but rather on primitives).
The closest you can get is some sort of operator aliasing, such as this:
/* Accepts a symbolic or string operator, returns a function which accepts numbers */
function operator(node)
{
//Mapping between string and symbol operators
var map = {"mod": "%", "mult": "*", "div": "/", "plus": "+", "minus": "-"}
//Return a function which applies the string or symbol operator to two numbers
return Function("x,y", "return x" + (map[node] || node) + "y");
}
// pass "*" to operator; pass 5,7 to returned function
var foo = operator("*")(5,7);
// pass "plus" to operator; pass 3,2 to returned function
var bar = operator("plus")(3,2);
// pass "mod" to operator; pass 1,0 to returned function
var baz = operator("mod")(1,0);
console.log(["foo",foo,"bar",bar,"baz",baz]); //["foo", 35, "bar", 5, "baz", NaN]
References
Can I define custom operator overloads in Javascript?
As an idea, you can try to write a parser yourself so you write some thing like this:
console.log(R("a * b"));
Where R is the function that converts a * b to a.mult(b) and then eval's this.
Related
Is there a way to parse math equations as input using JavaScript?
for example, when a user enters "10-25" as input, it is parsed to -15
I tried using eval, which works, but it allows users to run all JavaScript code, not just math equations.
If it's possible, I'd like to also allow some functions, like sin(), cos(), and degreesToRadians(), but not all functions.
examples
"5" //returns 5
"12-20" //returns -8
"3/2" //returns 1.5
"sin(3.14)" //returns 0.00159265292
"sin(degreesToRadians(180/2)) * 10" //returns 10
"alert('hi')" //doesn't work
You can split expression by math operations and check them.
Next code does it for: ( ) / *
mathExpression.replace(/([()/*])/g, " $1 ").split(" ").filter(v => v);
var allowedCommands = ["(", ")", /^\d*\.?\d*e?$/, "*", "/", "+", "-", "sin", "cos", "degreesToRadians"];
function checkCommand(arg) {
return allowedCommands.some(v => {
if (v instanceof RegExp) {
return v.test(arg)
} else {
return v == arg;
}
});
}
function checkAllowedCommands(mathExpression) {
var commands = mathExpression.replace(/([()/*+-])/g, " $1 ").split(" ").filter(v => v);
var filterNotAllowedCommands = commands.filter(v => !checkCommand(v));
return filterNotAllowedCommands.length == 0;
}
console.log(checkCommand("degreesToRadians"));
console.log(checkCommand("234"));
console.info("right expression");
console.info(checkAllowedCommands("sin(degreesToRadians(180/2)) * 10"));
console.info(checkAllowedCommands("(1.2e-6)"))
console.info(checkAllowedCommands("sin(1+2)"));
console.warn("wong expression");
console.info(checkAllowedCommands("alert('hi')"));
Perhaps something like this package: https://www.npmjs.com/package/nerdamer
I've used Nerdamer in a few projects in the past, and it's pretty solid. Short of that, there's no "simple" way to do it short of implementing your own mini-parser that I know of.
I have a simple JS function
let a = 0.33, c=13.89;
var res = calcRound(c*2+calcRound(a*2,1,1),1,1);
console.log(res);
function calcRound(value, figure, padding) {
let val = value;
let result = parseFloat(val);
result = result.toFixed(figure);
return result;
}
It returns a 27.8. But the answer should be 28.5
I have debugged the code. At first, it calculates this and it is correct
calcRound(a*2,1,1) = 0.7
Second time the '+' operator between c*2 and calcRound(a*2,1,1) gets lost.
it becomes like this 27.780.7 which should be like this 27.78+0.7
I know JS first evaluates the expression before sending it as an argument. My question is why the '+' operator is getting omitted?
+ is the concatenator operator in JS, it thinks the result from calcRound() is a string and behaves accordingly.
As mentioned by Andy in the comments, you can see in the
documentation for toFixed()
Return value: A string representing the given number using fixed-point
notation.
Change the return of your function to (to make sure it returns a number):
return Number( result );
let a = 0.33,
c = 13.89;
var res = calcRound(c * 2 + calcRound(a * 2, 1, 1), 1, 1);
console.log(res);
function calcRound(value, figure, padding) {
let val = value;
let result = parseFloat(val);
result = result.toFixed(figure);
return Number(result);
}
It's not getting omitted, JavaScript is treating them like strings and adding 27.78+0.7 as strings, you want to surround them in Number() or parseFloat() statements so that they are treated as numbers.
Like so:
calcRound(parseFloat(c*2) + parseFloat(calcRound(a*2,1,1)),1,1)
How do I add commas in between the inputs to make the function work?
function square(num) {
var items=str.split("")
return Math.abs(num*num - num2*num2)
}
square(4 2);
You can use
function square(num, num2) {
return Math.abs(num*num - num2*num2);
}
console.log(square(4, 2));
console.log(square(2, 4));
You can use Math absolute function:
function square(num, num2) {
var sq1 = num * num,
sq2 = num2 * num2;
return Math.abs(sq2-sq1);
}
To handle the problem that you didn't include in your question, you can pass a string into the square function, and handle like so:
function square(NUMBERS_STRING) {
var numbers = NUMBERS_STRING.split(" "),
sq1 = numbers[0] * numbers[0],
sq2 = numbers[1] * numbers[1];
return Math.abs(sq2-sq1);
}
Please, don't confused square("4 2") with square(4 2).
The second is not valid javascript.
May be worth pointing out that calling this function "square" may be a bad idea. If someone isn't used to your code and they see this function, are they going to know what it does outright? Maybe diffOfSquares(num, num2)?
My recommendation is to have the real mathematic function that'd be reusable in 99% of use cases:
function square(num, num2) {
num *= num;
num2 *= num2;
return Math.abs(num-num2);
}
And then for your overload call the above. Reason for this is that if something were to ever happen and the underlying logic found in function square(num, num2) required modifying, you would only modify it in one case and not for it plus every other overload. Here's how I'd do it for your current case:
function square(str) {
var items = str.split(" ");
return square(items[0], items[1]);
}
Optionally, but for the sake of reusability, what happens in the future if we get a string where they're pipe delimited? Comma delimited? I wouldn't want to break the code that assumed spacing, so I might modify that function to be:
function square(str, delim = " ") {
var items = str.split(delim);
return square(items[0].trim(), items[1].trim());
}
So if I call it, I could do:
square("4 2", " "); // space delimited
square("4 2"); // space delimited for legacy items
square("4, 2", ","); // comma delimited
square("4|2", "|"); // pipe delimited
I'm currently stuck on a Codewars challenge that I can't get my head around:
Given a string representation of two integers, return the string representation of those integers, e.g. sumStrings('1','2') // => '3'
I've used the following code so far, but it fails on large number test cases as the number is converted into a scientific notation:
function sumStrings(a,b) {
var res = +a + +b;
return res.toString();
}
Any help would be much appreciated.
Edit:
Fiddle example: https://jsfiddle.net/ag1z4x7d/
function sumStrings(a, b) { // sum for any length
function carry(value, index) { // cash & carry
if (!value) { // no value no fun
return; // leave shop
}
this[index] = (this[index] || 0) + value; // add value
if (this[index] > 9) { // carry necessary?
carry.bind(this)(this[index] / 10 | 0, index + 1); // better know this & go on
this[index] %= 10; // remind me later
}
}
var array1 = a.split('').map(Number).reverse(), // split stuff and reverse
array2 = b.split('').map(Number).reverse(); // here as well
array1.forEach(carry, array2); // loop baby, shop every item
return array2.reverse().join(''); // return right ordered sum
}
document.write(sumStrings('999', '9') + '<br>');
document.write(sumStrings('9', '999') + '<br>');
document.write(sumStrings('1', '9999999999999999999999999999999999999999999999999999') + '<br>');
The problem is that in that specific kata (IIRC), the numbers stored in a and b are too large for a regular 32 bit integer, and floating point arithmetic isn't exact. Therefore, your version does not return the correct value:
sumStrings('100000000000000000000', '1')
// returns '100000000000000000000' instead of '100000000000000000001'
You have to make sure that this does not happen. One way is to do an good old-fashioned carry-based addition and stay in the digit/character based world throughout the whole computation:
function sumStrings(a, b) {
var digits_a = a.split('')
var digits_b = b.split('')
...
}
Lets say I had a variable called test and test = 123456789;. Then I have another variable called anotherTest and anotherTest = 1234;. How would I make a program that can test whether a variable has the digit 5 or not? Then, how could it sort the variables into two groups of which one group of variables has the digit "5" within it and the other without? Is there a easy way to do this?
How would I make a program that can test whether a variable has the digit 5 or not?
You can readily do that with strings and indexOf:
if (String(test).indexOf("5") !== -1) {
// It has a 5 in it
}
Then, how could it sort the variables into two groups of which one group of variables has the digit "5" within it and the other without?
You can't sort the variables into groups, but you can certainly sort values into groups. For example, this loops through an array and adds values to either the with5 or without5 array depending on whether the value contains the digit 5:
var a = [
1234,
12345,
123123,
555555
];
var with5 = [];
var without5 = [];
a.forEach(function(value) {
if (String(value).indexOf("5") === -1) {
without5.push(value);
} else {
with5.push(value);
}
});
snippet.log("with5: " + with5.join(", "));
snippet.log("without5: " + without5.join(", "));
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
The above assumes base 10 (decimal) strings, but you can easily do the same with hexadecimal or octal or any other base you like by using Number#toString(base). E.g.:
var s = num.toString(16);
...will assign s the value of num as a hexadecimal (base 16) string.
Loop through each character of variable test, then compare using indexOf() to see if it exists in anotherTest. If so add to one array, otherwise add to array 2.
To see if a number contains the digit "5", you can just convert the numbers to strings and then just use .indexOf("5") on each string.
var test = 123456789;
var anotherTest = 1234;
// reports whether the passed in number or string contains the
// character "5"
function containsDigit5(val) {
// convert number to string
// if already string, then it is left as is
val = "" + val;
return val.indexOf("5") >= 0;
}
containsDigit5(test); // true
containsDigit5(anotherTest); // false
The grouping part of your question is not entirely clear, but you can just call this function on each variable and add the numbers to one of two arrays.
var testNumbers = [123456789, 1234];
var has5 = [];
var doesNotHave5 = [];
// reports whether the passed in number or string contains the
// character "5"
function containsDigit5(val) {
// convert number to string
// if already string, then it is left as is
val = "" + val;
return val.indexOf("5") >= 0;
}
testNumbers.forEach(function(item) {
if (containsDigit5(item)) {
has5.push(testNumbers[i]);
} else {
doesNotHave5.push(testNumbers[i]);
}
});
You can do this with RegExp, or .indexOf. Either works:
RegEx
Everyone hates RegExp for some reason, but I like it. You can use:
var test = 123456789,
anotherTest = 1234;
/5/.test(test);
/5/.test(anotherTest);
var test = 123456789,
anotherTest = 1234;
document.write( 'test (123456789): ' + /5/.test(test) + '<br/>' );
document.write( 'anotherTest (1234): ' + /5/.test(anotherTest) );
indexOf
This can be faster in some situations, but not always, it is also a bit more "complicated", at least in my opinion:
var test = 123456789,
anotherTest = 1234;
(test+'').indexOf(5) > -1;
(anotherTest+'').indexOf(5) > -1;
var test = 123456789,
anotherTest = 1234;
document.write( 'test (123456789): ' + ((test+'').indexOf(5) > -1) + '<br/>' );
document.write( 'anotherTest (1234): ' + ((anotherTest+'').indexOf(5) > -1) + '<br/>' );