I'm currently studying Javascript Algorithms. Below is the algorithm im currently trying to learn/understand.
function same(arr1, arr2){
if(arr1.length !== arr2.length){
return false;
}
let frequencyCounter1 = {}
let frequencyCounter2 = {}
for(let val of arr1){
frequencyCounter1[val] = (frequencyCounter1[val] || 0) +1
console.log(frequencyCounter1);
}
for(let val of arr2){
frequencyCounter2[val] = (frequencyCounter2[val] || 0) +1
}
for(let key in frequencyCounter1){
if(!(key ** 2 in frequencyCounter2)){
return false
}
if(frequencyCounter2[key ** 2] !== frequencyCounter1[key]){
return false
}
}
return true
}
same([1,2,3,2,5], [9,1,4,4,11])
I understand the code, except for 1 line.
frequencyCounter1[val] = (frequencyCounter1[val] || 0) +1
So what this algo does, is it tries compares 2 arrays. If array b is equal to the square of each number is array a, then it should return true, else it will return false.
So in this example, it will return false
If i do [1,2,3,4,5] [1,4,9,16,25], it will return true
I know what this line does:
frequencyCounter1[val] = (frequencyCounter1[val] || 0) +1
It makes a key value pair, so say for the first iteration, it makes take in 1 as the key and then (frequencyCounter1[val] || 0) +1 as the value, now this value represents the number of a times a number appears in array so if 1 appears 10 times it'll have a key value pair 1:10
I understand this very clearly, just wanted to know how this statement is evaluated and whats happening behind the scenes?
(frequencyCounter1[val] || 0) +1
The idea is that if frequencyCounter1[val] is undefined it defaults to 0. undefined + 1 returns NaN and it wouldn't work as the programmer intended, so he uses || to workaround that problem without having to write additional lines of code.
In JavaScript the operator || doesn't return true or false as you would expect, it returns either the first element that would evaluates as true if it was converted to boolean, or default to the last element if none is found.
For example, (null || "" || undefined || false || NaN || "test" || 2) will return "test"
This code is very unique in the sense that it starts with the first value of the array and checks if it already exists. If it does not exist, it is undefined. undefined is compared with 0 using the || operator. If undefined the val becomes registered and becomes 1.
Here we are basically setting the key:value pairs as seen in the below example
obj = {
1:1,
2:2,
3:5
}
obj[3] = 7
console.log(obj);
If val already exist the the OR operator is ignored and 1 is added to val. This one-liner is very useful as a counter operation in javaScript and the big O for the code is O(N) which is better than writing a nested loop O(N^2) which is a common solution for such problem.
Related
if (!value || value.length<1)
if (value.length<1)
What's the difference between the two conditions? Wouldn't it be same?
No, they are absolutely different.
!value
this checks for whether an item is present and it is not undefined, but ![] and also ![3] this is always false. basically it checks for presence.
and even [] is always true.
length
calculates the no of elements inside that array and it is purely applied to array.
for [] , value.length<1 this returns true.
If value is null or undefined, the second if will throw an error stating that you can't access length of null / undefined.
The first one prevents that, as it will only be accessing value.length if value is truthy. Otherwise, the first condition (!value) is satisfied, so the second one (value.length < 1) won't even be evaluated.
const arr1 = null;
const arr2 = [];
// Satisfies first condition:
if (!arr1 || arr1.length < 1) console.log('No values in arr1.');
// Satisfies second condition:
if (!arr2 || arr2.length < 1) console.log('No values in arr2.');
// Breaks:
if (arr1.length < 1) console.log('No values in arr1.');
Anyway, that's not specific to TS, it's just how vanilla JS works.
Quick way to understand is you cannot access length property of an undefined array. So the second if condition will throw an error akin to Cannot access property 'length' of undefined.
The first if condition however checks if the array is defined. So it won't throw any error.
Typescript contains a native way of doing this check using a "safe navigation operator" or optional chaining operator ?.. So in TS, you could simply do
if (value?.length < 1) { }
It is equivalent to JS
if ((value === null || value === void 0 ? void 0 : value.length) < 1) { }
This question already has answers here:
javascript array.sort with undefined values
(3 answers)
Closed 4 years ago.
I don't understand why the output of the code below separates the NaN to the beginning of the array and the undefined values to the end of the array. I'm coercing the NaN and undefined to 0 so I would expect for them to be collocated (grouped) together.
[9, undefined, NaN, undefined].sort(
function (a, b) {
// coercing NaN or undefined to 0
const first = (Number.isNaN(a) || a === undefined) ? 0 : a;
const second = (Number.isNaN(b) || b === undefined) ? 0 : b;
if (first < second) {
return -1;
} else if (first > second) {
return 1;
} else {
return 0;
}
}
)
actual output is
[
NaN,
9,
undefined,
undefined
]
expected output would be
[
9,
NaN,
undefined,
undefined
]
// or some variant where the NaN and undefined are grouped together
[
NaN,
undefined,
undefined
9,
]
update
From the linked duplicate answer, I kind of understand that undefined values have a special rule applied to them (where they are pushed to the end of the array), but it still seems odd that this rule of handling undefined values get applied before the comparator can have a chance at processing the undefined value.
Does anyone know if it's a pre-filter that's going on when Array.sort is invoked? Akin to
[undefined, 9]
.filter(x => x !== undefined)
.sort(...)
In which case, would it be less processing to simply remove the undefined values a priori, if I needed to call Array.sort multiple times on an array containing undefined values? I'm trying to get a sense of how the internals of Array.sort is behaving.
You do the array.sort in which first they simply ignore undefined and second you convert NaN to 0, so obviously in sort 0 comes first and 9 is second
In array.sort, all non-undefined array elements are sorted according
to the return value of the compare function (all undefined elements
are sorted to the end of the array, with no call to function)
More information : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#Description
var test = [9, undefined, NaN, undefined].sort(
function (a, b) {
// coercing NaN or undefined to 0
const first = (Number.isNaN(a) || a === undefined) ? 0 : a;
const second = (Number.isNaN(b) || b === undefined) ? 0 : b;
console.log(first, second);
if (first < second) {
return -1;
} else if (first > second) {
return 1;
} else {
return 0;
}
}
);
console.log(test);
I am trying to make a function which check the value if null or ""
Here is what I got so far (that is working)
function notnull(values,success,failed){
var count = 0
$.each(values,function(index,val){
console.log(val)
val != "" && val != null ? count++ : count
})
if(count == values.length){
return true;
}else{
console.log('false')
}
}
However If I tried short circuiting the 2nd if statement it returns an error
function notnull(values,success,failed){
var count = 0
$.each(values,function(index,val){
val != "" && val != null ? count++ : count
})(count == values.length) ? return true:console.log('false')
}
the error says
Uncaught SyntaxError: Unexpected token return
Question 1: How can I return true or false in a short circuit version
Question 2: at the code
val != "" && val != null ? count++ : count
How can I omit the else part?
Your second example is a bit messy, but if I understand your function, you want to go through each value and make sure none of them are null, right?
Here is your original, cleaned up a bit:
function notNull(values){
let count = 0;
$.each(values, function (index,val) {
(val != "" && val != null) ? count++ : count
});
return count == values.length; // returns true or false
}
You are basically going through each of the values, counting them up if they aren't null, and returning true if none were null (your count is the same as your array) or false otherwise.
You are using the jQuery equivalent of the vanilla each() function. They function the same way: they'll go through every single entry in an array.
You can't short-circuit each(). Instead, you need to use some() or every(). Those functions are similar, but opposite:
some() - Continues to loop through as long as its callback returns false.
every() - Continues to loop through as long as its callback returns true.
In your case, you want to use every() because you want to go through every element and make sure it is something (in your case, not null):
function notNull(values) {
return values.every((value) => value != "" && value != null);
}
console.log(notNull([1,2,3]));
console.log(notNull([1,null,3]));
Much nicer. This will check each value. As long as they match the condition, it'll keep going and ultimately return true. If if finds one that does match, it'll short circuit there and return false.
As for your second question, how can you leave out the "else" part of this:
val != "" && val != null ? count++ : count
With the ternary operator (?:), you can't. But, you can with the normal boolean operators:
val != "" && val != null && count++;
JavaScript will short-circuit that condition at the first false, so it'll only get to count++ if the other two bits are true.
On your second example, I think you were attempting something like:
condition ? return value : console.log('a')
This would be an invalid syntax. You can only have values inside of a ternary. You could do something like this:
return condition ? value : otherValue;
If you want a return mixed in, you have to do it as two separate things:
!condition && console.log(''); // log if false;
if (condition) return value;
return and throw are both stubborn in this way and always have to be broken out and can't be mixed with other selective operators.
Given two arrays myArray1 and myArray2, which may be null, how can I output a Boolean which tells me if at least one array is non-empty?
Assuming that I have the following variables:
myArray1 = ["one", "two", "three"]; //-> non-empty array
myArray2 = null; //-> not an array (in my case this happens from .match() returning no results)
I want an expression, such that myArray1 && myArray2 will be FALSE, but myArray1 || myArray2 will be TRUE.
I did look through other relevant Stack Overflow questions (see an abridged list below), but since I still struggled to figure out the solution, I thought I would post it as a separate question since answers might also benefit others.
The common way of testing for empty arrays is:
myBooleanOr = (myArray1.length || myArray2.length); //3
myBooleanAnd = (myArray1.length && myArray2.length); //Error
This works if both variables are arrays, but in this case, the second one will throw up Error: cannot read property length of 'null'. Using the Boolean() function does not solve the problem since the following also throws up the same error:
myBooleanAnd = (Boolean(myArray1.length) && Boolean(myArray2.length)); //error
A solution for testing empty arrays which was accepted in several Stack Overflow questions is to use typeof myArray !== "undefined", but that still does not solve the problem, because neither of the arrays match "undefined", so myBooleanAnd will still throw up an error:
var bool = (typeof myArray1 !== "undefined"); //true
var bool = (typeof myArray2 !== "undefined"); //true
var myBooleanAnd = ((typeof myArray1 !== "undefined" && myArray1.length) || (typeof myArray2 !== "undefined" && myArray2.length)); //Error: cannot read property length of null
Comparing the arrays against [], which also seems intuitive, also doesn't work, because neither of the arrays match []:
var bool = (myArray1 !== []); //true
var bool = (myArray2 !== []); //true
Other relevant posts
A number of other questions on Stack Overflow deal with testing for empty Javascript arrays, including:
Testing for empty arrays: Check if array is empty or exists
Testing for empty arrays (jQuery): Check if array is empty or null
Relative advantages of methods for testing empty arrays: Testing for an empty array
Testing for empty objects: How do I test for an empty JavaScript object?
And there are also questions about the truth value of empty arrays in Javascript:
JavaScript: empty array, [ ] evaluates to true in conditional structures. Why is this?
UPDATE
I have corrected the following errors posted in the original question (thanks to those who pointed them out). I am listing them here since they might also be helpful to others:
==! changed to !==
typeof x === undefined, changed to typeof x === "undefined"
I would suggest using a helper function to determine if a single array is non-empty, and then use that twice. This is simple and straightforward:
function isNonEmptyArray(arr) {
return !!(Array.isArray(arr) && arr.length);
}
var myBooleanAnd = isNonEmptyArray(myArray1) && isNonEmptyArray(myArray2);
var myBooleanOr = isNonEmptyArray(myArray1) || isNonEmptyArray(myArray2);
Ok, so, there're a bunch of errors in the code examples, i'll try to to explain them all:
myBooleanOr = (myArray1.length || myArray2.length); //3
myBooleanAnd = (myArray1.length && myArray2.length); //Error
Here, the first line returns the first truthy value it encounters. Since myArray1 has a length > 0, it returns that value and never evaluates the second part of the condition, that's why you're not getting the error. Swap the checks and it will break.
The second line combines the two values to give a result, so it will always give an error when one of the two variables are null.
var bool = (typeof myArray1 === undefined); //false
typeof returns a string, if you compare it to the undefined constant it will always be false, the correct statement is typeof myArray1 === "undefined" as written in most of the posts you linked
var bool = (myArray2 ==! null);
the "strictly not equal" operator is !== and NOT ==!. You're doing a different operation and that's why you get surprising results.
Putting the right spaces in the syntax, this is your code var bool = (myArray2 == !null);
So you boolean-flip the value of null, which is falsy by nature, getting true, and then compare if myArray2 is loosely-equal to true ... since myArray2 is null, and that is falsy as we said, the comparison gives back a false.
That said, for the solution to the question, I'd propose a slightly longer syntax that is more explicit, clear to understand, and you can scale to check how many arrays you like without adding more complexity:
var myArray1 = [1,2,3]
var myArray2 = null
var arrays = [myArray1, myArray2]
var oneNotEmpty = arrays.some( a => typeof a != "undefined" && a != null && a.length > 0)
console.log("At least one array non-empty?", oneNotEmpty)
You could use isArray to check something is an array or not. Most modern browsers supports it. https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
And then you can combine isArray and array's length to check if something is a valid non empty array or not.
function isOneNotEmpty(arrayOne, arrayTwo){
return (Array.isArray(arrayOne)? arrayOne.length > 0 : false) || (Array.isArray(arrayTwo)? arrayOne.length > 0 : false)
}
console.log(isOneNotEmpty([],null));
console.log(isOneNotEmpty([1,2,3,4],null));
console.log(isOneNotEmpty([3,4,5],[1]));
Testing for an array is simple enough:
var blnIsPopulatedArray = (myArray != null
&& typeof myArray == "object"
&& typeof myArray.length == "number"
&& myArray.length > 0);
Will return false if 'myArray' isn't an array with at least one item, or true if it is an array with at least one item.
One solution is the following (with or without Boolean()):
Using Array.isArray() and array.length:
var myBooleanAnd = Boolean(Array.isArray(myArray2) && myArray2.length) && Boolean(Array.isArray(myArray1) && myArray1.length) ; //false -> OK
var myBooleanOr = Boolean(Array.isArray(myArray2) && myArray2.length) || Boolean(Array.isArray(myArray1) && myArray1.length) ; //true -> OK
It is also possible to use myArray1 !== null instead of Array.isArray(myArray1), but since the latter is a more specific test, the broader Array.isArray() method seems preferable.
UPDATE
I had previously suggested using the following:
var myBooleanAnd = Boolean(myArray1 && myArray2); //returns false -> OK
var myBooleanOr = Boolean(myArray1 || myArray2); //returns true -> OK
but since, as pointed out by #JLRishe, the following expression also returns TRUE, this is not a safe solution, since it will only work in situations where the arrays can never be empty.
var bool = Boolean([] && []); //returns true -> false positive
function arrayIsEmpty(array) {
if (!Array.isArray(array)) {
return false;
}
if (array.length == 0) {
return true;
}
}
I have a situation where I am searching for something in an array, and if a value is found, I do something. I am doing this by setting a variable to undefined, and then when the value is found, setting to the index of the element found. This would work if the value returned is anything but 0, but if it is 0, then it returns as false. How can I work around this?
var index = undefined;
for(var i=0; i<ARRAY; i++)
{
if(CONDITION)
index = i;
}
if(index)
{
DO SOMETHING
}
So my problem occurred when the index turned out to be zero, because this returned false. The reason I want to do it this way is because I am not sure if it exists in the array or not.
How about testing the result to see whether it's >= 0 instead of relying on its truthyness?
if (index >= 0) { ... }
The undefined value is not >= 0 so that should work.
Why not be 100% explicit? This is, after all, what you're actually intending to check:
if (typeof index === 'number')
{
// DO SOMETHING
}
I prefer this even to checking >= 0 since that operator gives some weird results for non-numeric values:
Input | >= 0
------------
"1" | true
false | true
null | true
[] | true
"" | true
(See this jsFiddle for evidence.)
You mean you have a variable that may be undefined or some number, and you want undefined to be distinguishable from 0?
Then:
if (index) // wrong
if (index >= 0) // right
Or you can use type-aware comparisons:
if (index !== undefined) { .. }
You can use -1 to indicate the index was not found in the array. As you mentioned, 0 will be implicitly cast to a "false" if you use it like a boolean. You can use === to avoid an implicit cast.
You could... not do it like that, because you need to work within JS's definition of truthiness, or check explicitly for undefined.
0 is falsey in javascript; use === to test whether a value is actually false:
foo = 0;
foo == false //true
foo === false //false
As you're setting the value to undefined one way of testing is to see whether the value is Not a Number:
if (!isNaN(foo))
{
//foo is numeric
}
I wrote these simple utility functions to help with more math-oriented tasks:
function isFalsy(val) {
return (((!val)&&(val!==0))||(val === null)||(val === NaN)||(val === ""))
}
function isTruthy(val) {
return !isFalsy(val)
}