I was doing a code kata which involves taking an array of football scores e.g.
["3:1", "2:2"] (Total points here would be 4, 3 + 1)
and applying some rules and then summing up the points. One of the solutions was:
const points = g => g.reduce((a, [x, _, y]) => a + (x > y ? 3 : x == y), 0)
To clarify, the rules are, if 1st value is greater than 2nd return 3, if equal return 1, else return 0, similar to a football match scoring system.
How does the part "x == y" work in this case, the rule here is that if "x == y" then a single point should be returned.
If someone can explain this in a simple way with an example, that would help me, thanks.
On a side note if someone can explain the "[x, _, y]" I would also appreciate that. I understand it's supposed to represent the current item in the array, but the current item is a string, not an array, so what is happening here?
This comes down to how JavaScript interprets true and false. Try in the console the following:
let x = 1;
let y = 2;
2 + (x == y);
What do we expect here? x == y is evaluated to false so that last line is really:
2 + (false);
Then to resolve the addition it coerces that false into a number. In JavaScript false is 0. So its actually:
2 + 0
Now try this:
let x = 1;
let y = 1;
2 + (x == y);
And what do we expect now? Since x == y will now evaluate to true and true will be coerced into a 1 this is actually:
2 + 1;
It is destructuring the string
x is the first char, _ is an unused variable and y is the 3rd;
const [x, _, y] = "3:1";
console.log(x);
console.log(_);
console.log(y);
It's just a quirky type coercion side-effect of JavaScript.
true can be coerced to 1 when used like this in an arithmetic operation:
console.log('hi' == 'hi'); // true
console.log(0 + (true)); // 1
console.log(0 + ('hi' == 'hi')); // 1
Here is a node session for you to study. First it shows modern JS string-to-array destructuring, second it shows some boolean behavior.
micha#linux-micha: ~
$ node
> [...arr] = "hello";
'hello'
> [...arr]
[ 'h', 'e', 'l', 'l', 'o' ]
> [x, dummy, y] = "3:2"
'3:2'
> x
'3'
> y
'2'
> dummy
':'
> typeof (x == y)
'boolean'
> typeof true
'boolean'
> typeof false
'boolean'
> 1 + true
2
> 1 + false
1
>
As you can see from that node session, "2:2" undergoes string-to-array destructuring, which results in x=2, y=2. Hence,x==y is boolean true. Now, there's a + (... x==y) in the function body, so the true value (aka x==y) is converted to a numerical 1 value, due to the + (plus) operator. So, a single point is returned.
Regards, M.
The String values are kind of arrays (iterables) with indexes, so you can access the indexes:
So, you can destructure strings.
console.log("3:1"[0]);
console.log("3:1"[1]);
console.log("3:1"[2]);
.as-console-wrapper { max-height: 100% !important; top: 0; }
In your case, this is getting the first, second and third index [x, _, y]
let [x, _, y] = "3:1";
console.log(x, _, y);
This a + (x == y) is called coercion, true -> 1 and false -> 0.
console.log(1 + false);
console.log(1 + true);
Related
I'm trying to write this code for an after effects expression that will move an object a calculated x distance over n number of frames. The movement over each frame is parabolic rather than linear, and so I'm using the nth root code to determine how much the object should move over each frame. I'm putting each of the nth roots into an array to access later when setting the positions for each move.
I'm still learning javascript mainly for AE, so please bear with me if there are things in here I don't fully understand. I think I understand, which is why I'm not sure I'm getting the undefined output for certain n values. Here's the code:
//get Nth root
function nthroot(x, n) {
ng = n % 2;
if ((ng == 1) || x < 0)
x = -x;
var r = Math.pow(x, 1 / n);
n = Math.pow(r, n);
if (Math.abs(x - n) < 1 && (x > 0 === n > 0))
return ng ? -r : r;
}
distance=1515; //will be determined by another portion of the AE expression
frames=6; //will be set by expression control in AE
const myArray = [];
let i = 1;
while (i <= 6) {
myArray.push(nthroot(distance,i++));
}
console.log(myArray);
document.getElementById("demo2").innerHTML = myArray
I put it into a fiddle here. What am I doing wrong? Thanks in advance for any help!
Your "nthroot" function doesn't return values consisistently: if you look at the end of your function you can find this part:
if (Math.abs(x - n) < 1 && (x > 0 === n > 0))
return ng ? -r : r;
if you notice, you are returning a value only if the condition in the if statement is fullfilled, otherwise you are not returning any value.
In JavaScript, a function that doesn't return any value returns "undefined" instead.
In other words, when
Math.abs(x - n) < 1 && (x > 0 === n > 0)
is true, you are returning either "r" or "-r", but when the condition is false you aren't returning any value, so the function returns "undefined".
You have to handle the false case.
I was writing an algorithm to compare how many bits are different between 2 numbers using this function
var hammingDistance = function(x, y) {
let result = 0;
while (x !== 0 || y !== 0) {
// This line is incorrect
if (x & 1 !== y & 1) result++;
x = x >> 1;
y = y >> 1;
}
return result;
};
But my result is always 1 less than the correct answer, and it turns our my function is wrong when comparing the left most digit, such as 0011 and 0100. It returns 2 instead of 3.
https://i.imgur.com/P46RyZr.png
I can use XOR instead of !== to get the correct answer. But I'm wondering why?
Your problem is that !== has a higher precedence than &. So your condition is actually (x & (1 !== y)) & 1. Use explicit grouping instead:
if ((x & 1) !== (y & 1)) result++;
It works with ^ because that has a lower precedence than &.
How would i check if a decimal is negative? Because the if statement automatically turns it into a number...
Example:
var x = -0.24324;
how would i parse it so it tells me x is negative/positive?
Thanks
Edit: Maybe i phrased it badly, the variable changes so something it will be positive like 0.00000001, sometimes -0.0003423423, sometimes 0.0000000234
If i put it in a if statement everything is automatically turned into 0 right? And i can't use a parseFloat in the if statement?
Just check if x less than zero since it's a number:
if (x < 0) {
// it's negative
}
You can use isNaN() function to check whether it is valid number or not.
If it is, then you can check for positive or negative value.
Something like this:
var x = "-123"
var y = -456;
var z = '-123a';
if(!isNaN(x) && x < 0) {
console.log(x + ' is negative');
}
if(!isNaN(y) && y < 0) {
console.log(y + ' is negative');
}
if(!isNaN(z) && z < 0) {
console.log(z + ' is negative');
}
const num = -8;
// Old Way
num === 0 ? num : (num > 0 ? 1 : -1); // -1
// ✅ ES6 Way
Math.sign(num); // -1
what value should X have so this condition would work?
// insert code here
if (x == 1 && x === 2) {
console.log('Succes!');
}
X should be defined like so:
Object.defineProperty(window,'x',{
get: function() {
this.__tmp = this.__tmp || 2;
this.__tmp = 3-this.__tmp;
return this.__tmp;
}
});
Then:
if( x == 1 && x === 2)
MIGHT work. Demonstration
The following code should do the trick (Demo here):
x = {};
x.valueOf = function (){
x = 2; // this is important
return 1;
};
if (x == 1 && x === 2) {
console.log('Success !!!');
}
Explanation:
The statements are executed from left to right (so first x == 1, then x === 2). When checking x == 1, it will go to the valueOf function, which returns 1, so it will be true. But at the same time, x is changed to be 2, thus the next statement that will be checked (x === 2) will also be true.
PS: As far as I know, this has no practical application. However, it can lead to better understanding of how javascript works - which is the point of such questions :)
X can't hold a value equals to 1 and identical to 2 at the same time, this expression is logically incorrect.
There is no such value.
x === 2 checks if x equals exactly to 2, while 2 cannot be 1 at the same time.
Only the following would make sense:
if (x && x === 2) { ... }
(or getter overloading, as demonstrated in #Niet the Dark Absol's answer, which is not a pure case)
Using === (identity) operator it will never work, but it's possible to construct an object that will be "equal" (==) to 1 and 2 at the same time:
x = { valueOf: function() { return this.foo ? 2 : this.foo = 1 } }
console.log(x == 1 && x == 2) // true
"valueOf" is the method JS implicitly calls when you convert or compare an object to a number.
Needless to say, this exercise doesn't have any practical sense.
In ActionScript 1 and 2, if you compare undefined, null or NaN with an arbitrary number using >= or <= operator, the result is always true. Test code:
var x, n, range = 1000;
for (var i = 0; i < 3; ++i) {
switch (i) {
case 0:
x = undefined;
break;
case 1:
x = null;
break;
case 2:
x = NaN;
break;
}
n = range*Math.random();
trace(x + ' >= ' + n + ': ' + (x >= n));
n = range*Math.random();
trace(x + ' <= ' + n + ': ' + (x <= n));
}
Furthermore, isNaN(null) return true.
These are contrary to JavaScript and may not conform with ECMA standard.
Are these bugs or intention?
Thanks!
Since ActionScript 2 knows only one numerical type, Number, all the non-numerical elements in your comparisons are cast to Number - which would be the same as writing:
Number (null) <= n
Number (undefined) <= n
Number (NaN) <= n
Number ({anything but a number}) always returns NaN, therefore all your statements really only compare random Numbers with NaN. The ActionScript documentation clearly warns about NaN not being comparable, and advises to always use isNaN() to test for it.
If you do compare with NaN, however, it is a strange thing in AS2:
NaN == Number // returns false
NaN != Number // returns true
These behave as expected, but:
NaN >= Number // returns true
NaN <= Number // returns true
and finally:
NaN > Number // returns undefined
NaN < Number // returns undefined
Of course that is not very intuitive - any comparison with NaN should always be false, and that has been fixed in AS 3 - but it makes absolute sense that null is not a Number, and hence isNaN(null) should return true.