Here is a lisp procedure that simply adds 'a' to the absolute value of 'b':
(define (a-plus-abs-b a b)
((if (> b 0) + -) a b))
I think this is beautiful, and I am trying to find the best way of writing this in JavaScript. But my JavaScript code is not beautiful:
var plus = function(a,b) {
return a + b;
};
var minus = function(a,b) {
return a - b;
};
var aPlusAbsB = function(a,b) {
return (b > 0 ? plus : minus)(a,b);
}
The main problem is that I cannot use the + and - symbols as references to the functions they really represent as I can with lisp. Can anyone come up with a more graceful way of doing something like this, or have I hit a language boundary?
Obviously, I can do this:
var aPlusAbsB = function(a,b) {
return a + Math.abs(b);
}
, but this is more of a thought experiment than a pragmatic question.
Is there any way I can get reference to the core functions in the JavaScript language just as if they were user-defined?
It's a very cool idea - would be great for evaluating mathematical expressions but you simply can't set an operator (or the logic behind it) to a variable. Sorry :-)
It depends on what aspects of the lisp implementation you find particularly beautiful. I'll propose another version of your suggestion that I think ends up a little closer to your lisp definition's syntax by doing some dirty things.
// Give ourselves + and - functions to level the playing field with lisp.
Number.prototype['+'] = function(x)this+x;
Number.prototype['-'] = function(x)this-x;
// Now we can have some fun.
var aPlusAbsB = function(a,b) a [b > 0 ? '+' : '-'] (b);
// Some other notable language barrier differences, but not too dissimilar?
// (define (a-plus-abs-b a b) ((if (> b 0) + -) a b))
Though not as elegant as the LISP code, you could create a function dynamically that acts like an operator (on numbers), but it's not.
function op(o) {
return new Function("a", "b", "return a " + o + " b");
}
function aPlusAbsB(a, b) {
return (b > 0 ? op('+') : op('-'))(a, b);
}
Additionally, we can hide the complexity of generating these inside an if wrapper, but that's the closest I can get :)
function is(expr, op1, op2) {
return expr ? op(op1) : op(op2);
}
function aPlusAbsB(a, b) {
return (is(b > 0, '+', '-')(a, b));
}
I think everyone else got here first, but JS is slightly less purely functional than lisp, operators are not functions or objects, but operators.
This is slightly more beautiful than your suggestion, though nowhere near as beautiful as your lisp representation of the concept:
var aPlusAbsB = function(a, b) {
var plus = function(a, b) {
return a + b;
};
var minus = function(a, b) {
return a - b;
};
return (b > 0 ? plus : minus)(a, b);
}
This would be equivalent to the following in scheme:
(define a-plus-abs-b
(lambda (a b)
(let ((plus (lambda (a b) (+ a b))) (minus (lambda (a b) (- a b))))
(cond ((> b 0) (plus a b))
(else (minus a b))))))
Yeah, that's not strictly possible, the closest thing you can do is nest addition and subtraction functions inside.
var aPlusAbsB = function(a, b) {
return (function(a, b) { b > 0 ? a + b : a - b })(a, b);
}
Not exactly the same, but it gets the job done in a sufficiently indirect way.
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, "👎");
Can I only use if and else in a statement in ternary operator syntax or can I also somehow include an else if?
example:
if(a) {
x
}
else if(y) {
c
}
else {
b
}
Unlike an if with optional else or optional else if branches, a ternary operator has two and only two branches.
It's actually a part of the name. Where + in a + b is a binary operator, that is it has two operands, ? has three, as in a ? b : c, and is termed ternary because of that. Technically there could be other ternary operators beyond ? but in most languages they don't exist, so it is generally understood that the name "ternary" means the ? operator.
You can have else if like functionality if you sub-branch the second clause:
a ? b : (c ? d : e)
This is usually a bad idea as ternary operations can be messy to start with and layering like this is usually an express train to unmaintainable code.
It is much better to write:
if (a) {
b
}
else if (c) {
{
d
}
else {
e
}
This is more verbose, but abundantly clear.
If you use ternaries too agressively you'll end up with code like:
a()?c?d?e:f:g:h?i(j?k:l?m:n):o
Where it's anyone's guess what's going on in there.
It's very much possible!
You could use this:
a ? b : b ? c : d
You could stack multiple ternaries:
var x = (y) ? 1 : ( (z) ? 2 : 0 );
Is there a way to translate something like the following logical operation (which uses a string due to user input)? Or will I have to check for every possibility? (> < => == =< etc.)
var x = 5;
var y = 3;
var operator = '>'
if (x operator y)
doSomething();
|
|
v
if (x > y)
doSomething();
Yes, with an object and appropriate functions, like
var comparer = {
'>': function (a, b) { return a > b; }
};
Use:
if (comparer[operator](x, y)) {
doSomething();
}
You could use eval, providing you know that it is evil. Though you should definitely check if the input is valid, for example checking if it only contains the '><=' characters.
You should change your way.
With eval you must whitelist all operators and sanitize both inputs.
Build your own interface for your needs.
May be it will switch:
switch (operator) {
case '>': if (x > y) doSomething();
}
May be some more abstracted like:
ifArg(x).relatedWith(y).as(operator).then(doSomething);
May be even you'll write your own small interpreter(parser/lexer) and your users will can to write program on it.
It will be used in an web application where users can create there own
small (simple) applications for the use of data. – Mathieu Brouwers
What you should not to use here is eval.
In javascript:
"Id".localeCompare("id")
will report that "id" is bigger. I want to do ordinal (not locale) compare such that "Id" is bigger. This is similar to String.CompareOrdinal in C#. How can I do it?
I support the answers given by Raymond Chen and pst. I will back them up with documentation from my favorite site for answers to JavaScript questions -- The Mozilla Developer Network. As an aside, I would highly recommend this site for any future JavaScript questions you may have.
Now, if you go to the MDN section entitled String, under the section "Comparing strings", you will find this description:
C developers have the strcmp() function for comparing strings. In JavaScript, you just use the less-than and greater-than operators:
var a = "a";
var b = "b";
if (a < b) // true
print(a + " is less than " + b);
else if (a > b)
print(a + " is greater than " + b);
else
print(a + " and " + b + " are equal.");
A similar result can be achieved using the localeCompare method inherited by String instances.
If we were to use the string "Id" for a and "id" for b then we would get the following result:
"Id is less than id"
This is the same result that Yaron got earlier when using the localeCompare method. As noted in MDN, using the less-than and greater-than operators yields similar results as using localeCompare.
Therefore, the answer to Yaron's question is to use the less-than (<) and greater-than (>) operators to do an ordinal comparison of strings in JavaScript.
Since Yaron mentioned the C# method String.CompareOrdinal, I would like to point out that this method produces exactly the same results as the above JavaScript. According to the MSDN C# documentation, the String.CompareOrdinal(String, String) method "Compares two specified String objects by evaluating the numeric values of the corresponding Char objects in each string." So the two String parameters are compared using the numeric (ASCII) values of the individual characters.
If we use the original example by Yaron Naveh in C#, we have:
int result = String.CompareOrdinal("Id", "id");
The value of result is an int that is less than zero, and is probably -32 because the difference between "I" (0x49) and "i" (0x69) is -0x20 = -32. So, lexically "Id" is less than "id", which is the same result we got earlier.
As Raymond noted (and explained) in a comment, an "ordinal" non-locale aware compare is as simple as using the various equality operators on strings (just make sure both operands are strings):
"a" > "b" // false
"b" > "a" // true
To get a little fancy (or don't muck with [[prototype]], the function is the same):
String.prototype.compare = function (a, b) {
return ((a == b ? 0)
? (a > b : 1)
: -1)
}
Then:
"a".compare("b") // -1
Happy coding.
Just a guess: by inverting case on all letters?
function compareOrdinal(ori,des){
for(var index=0;index<ori.length&&index<des.length;index++){
if(des[index].charCodeAt(0)<ori[index].charCodeAt(0)){
return -1;
break;
}
}
if(parseInt(index)===des.length-1){
return 0;
}
return 1;
}
compareOrdinal("idd","id");//output 1
if you need to compare and find difference between two string, please check this:
function findMissingString() {
var str1 = arguments[0];
var str2 = arguments[1];
var i = 0 ;
var j = 0 ;
var text = '' ;
while(i != (str1.length >= str2.length ? str1.length : str2.length )) {
if(str1.charAt(i) == str2.charAt(j)) {
i+=1 ;
j+=1;
} else {
var indexing = (str1.length >= str2.length ? str1.charAt(i) : str2.charAt(j));
text = text + indexing ;
i+=1;
j+=1;
}
}
console.log("From Text = " + text);
}
findMissingString("Hello","Hello world");
Is this valid JavaScript? I saw an example where someone used commas in the ternary operator conditions, and it was marked as an error in my editor, and the example didn't run in Chrome. However, it did run in Firefox. Once I converted all the ternary statements to if/else statements, the app ran on Chrome.
a!==b ? (a=1, b=2) : (a=2, b=1)
Edit:
This is the actual statement in the code:
a!==0?b<0?(h=b/a,e=h-1,f=-2*b+2*a*e,i=-2*b+2*a*h,d=2*h*a-2*b-2*a):(h=b/a,e=h+1,f=2*b-2*a*e,i=2*b-2*a*h,d=-2*h*a+2*b):d=h=e=f=i=0
Yes, it's valid, and it runs fine in Chrome:
var a, b, c;
a = 6;
b = 7;
c = a !== b ? (a = 1, b = 2) : (a = 2, b = 1);
console.log("a = " + a);
console.log("b = " + b);
console.log("c = " + c);
I'm not saying it's a remotely good idea in code humans are meant to read. :-) I expect jamietre is correct in the comments when he/she says it looks like the result of minification.
The comma operator is a binary operator (an operator accepting two operands). It evaluates its left-hand operand (thus causing any side-effects it has, such as assignment), throws that result away, then evalutes its right-hand operand (thus causing its side-effects if any) and takes that result as its result value. If you have multiple comma operators in a row, the overall expression is evaluated in order, left-to-right, with the final result being the value resulting from the right-most operand evaluation.
And of course, you know the conditional operator (a ternary operator — one accepting three operands) is used to pick one of two sub-expressions to evaluate, on the basis of an initial expression.
So that line is very...expressive...what with a total of seven* different expressions inside it.
So in that example, the result of the overall expression is 2 if a !== b initially, or 1 if a === b initially, with the side-effects of setting a and b.
It's the side effects that make it, in my view, a questionable choice. And of course, there's no reason to use the comma operator if the left-hand operand doesn't have side effects.
* Yes, seven of 'em packed into that overall ternary:
a !== b
the first comma expression
a = 1
b = 2
the second comma expression
a = 2
b = 1
Re your edit with the actual statement, that one works too:
function test(a) {
var b = 7,
d = 1,
e = 2,
f = 3,
g = 4,
h = 5,
i = 6;
a!==0?b<0?(h=b/a,e=h-1,f=-2*b+2*a*e,i=-2*b+2*a*h,d=2*h*a-2*b-2*a):(h=b/a,e=h+1,f=2*b-2*a*e,i=2*b-2*a*h,d=-2*h*a+2*b):d=h=e=f=i=0;
console.log("a = " + a);
console.log("b = " + b);
console.log("d = " + d);
console.log("e = " + e);
console.log("f = " + f);
console.log("g = " + g);
console.log("h = " + h);
console.log("i = " + i);
}
test(0);
test(1);
.as-console-wrapper {
max-height: 100% !important;
}
But wow, I hope this is minified, because if a person wrote that, they must really have a thing against anyone who's supposed to maintain it later... ;-)
Yes:
a=1;
b=2;
a!==b ? (a=1, b=2) : (a=2, b=1)
console.log(a); // 1
console.log(b); // 2
and:
a=1;
b=2;
a===b ? (a=1, b=2) : (a=2, b=1)
console.log(a); // 2
console.log(b); // 1
As you can analyze, changing the equality operator reacts correctly to our test if you look at the results.
Or you can do this :
b = a!==b ? (a=1,2) : (a=2,1);
Read here about comma operator.
The comma operator evaluates each of its operands (from left to right) and returns the value of the last operand.
Expanding on this topic with ES6 code example. If you're using one side of the TRUE : FALSE argument to iterate thru all cases in one IF, it makes sense to separate the code as if it's a switch | case statement.
Nesting implies that there is branching logic, while it is logically nested, writing nested IF's complicates what we're doing in my example. Like a lawyer over explaining a problem to a jury. IMO, you want to explain the point in it's simplest form. For instance, I find this example the most logical way of expressing nested ifs where the TRUE is executed. The final false is your last else {}
choreDoor is either 0,1 or 2:
choreDoor === 0 ?
(openDoor1 = botDoorPath,
openDoor2 = beachDoorPath,
openDoor3 = spaceDoorPath)
: choreDoor === 1 ?
(openDoor2 = botDoorPath,
openDoor1 = beachDoorPath,
openDoor3 = spaceDoorPath)
: choreDoor === 2 ?
(openDoor3 = botDoorPath,
openDoor1 = beachDoorPath,
openDoor2 = spaceDoorPath)
: false;
If you don't want to use the Comma operator (,) then you can use nested Conditional (ternary) operators instead.
var a = 6;
var b = 7;
var c = (a !== b)? // true
((a = 1 || 1===1)? (b = 2) : null) // will first run a=1, then b=2
: ((a = 0 || 1===1)? (b = 0) : null);
console.log("a = " + a);
console.log("b = " + b);
console.log("c = " + c);