combine multiple && conditions into 1 - javascript

Is there a better way in Javascript to do null check on multiple elements I want to
a=null; b=null;....n=null;
So in total I have 14 variables set to null initially and I want to apply just one solution to all of them if they are ```null``.
if (a=== null && b=== null&& c=== null&& d=== null&& e=== null &&...&& n===null){
// set some field to false
}
is there a better way to check for null, as this may get cumbersome if we have more arrays added
Thanks!

Create a an array of arrays, iterate it using Array.every(), and do something if all item values are null:
if([a, b, c, ... n].every(a => a === null)) {
// set some field to false
}

If you're new to JS, in JS, values can be "falsey" or "truthy". if / while / for will run if the value it's supposed to evaluates to "truthy." There are few "falsey" values in JS, and the rest are considered "truthy." The false values are:
undefined
0
NaN
null
''
false
(I believe I got them all. Think of "six sins": there are six of these)
So check the following code, and what their outcomes are:
if(0) console.log('yay') // won't run
if(false) console.log('yay') // won't run
if(null) console.log('yay') // won't run
if('') console.log('yay') // won't run
if(NaN) console.log('yay') // won't run
if([]) console.log('yay') // will run
if('0') console.log('yay') // will run
This is a long winded way of saying if you want to do something based on whether array is empty or not, try the following:
let arr = [1,2,3,4]
if(arr.length){
//do stuff if array is not empty
} else {
// do stuff if array is empty
}
Now to actually solve the problem for you, do the following:
const masterArray = [a, b, c, d, ... , n];
let length = 0;
masterArray.forEach(subarr=>{
length += subarr.length;
})
//At this point, if no array had any elements, length would be 0
if(length === 0){
// do stuff
}

Related

Deeply equal function error in Javascript

I am trying to create a function to check whether two arrays are deeply equal to each other.
An example would be: [1, 2, { a: "hello" }] and [1, 2, { a: "bye" }] would return false.
This is my code so far:
const deeplyEquals = (val1, val2) => {
let counter = 0;
for (var i = 0; i < val1.length; i++) {
if (typeof val1[i] === "object") {
deeplyEquals(JSON.stringify(val1[i]), JSON.stringify(val2[i]));
} else if (typeof val2[i] === "object") {
deeplyEquals(JSON.stringify(val1[i]), JSON.stringify(val2[i]));
} else if (val1[i] !== val2[i]) {
counter++;
}
}
return counter === 0 ? true : false;
};
I implemented a counter so that if it found a value in 1 that was not equal to the same value in 2 then it would increment. If the counter was not 0 then it would return false.
For the example, the counter increments to 7 but then right at the end, changes to 0 and therefore returns true instead of false.
I'm sure there would be an easier way to do this but I was wanting to see whether I could make this work as I am unsure why the counter is changing to 0 right at the end.
Thanks for any help!
The problem is that the counter is local to each call to deeplyEquals. There's a different counter for each call, and since you're making the calls recursively, you have lots of different counter variables in memory at the same time.
If you wanted to maintain a counter, you'd have to have each recursive call return the counter value (instead of a flag) so the code calling it could increment its counter by that much.
But there's no need in your code. Instead, just return false the first time you find a difference, either during in the call itself or in one of its recursive calls by checking the return value of the recursive call.
There are other issues with the code. Here's what I notice off-the-cuff:
You're calling JSON.stringify, which returns a string, before passing values to deeplyEquals, which will convert arrays and objects to strings. Comparing the strings won't be reliable (because equivalent objects can have their properties in different orders: JSON.stringify({a:1,b:2}) is the string {"a":1,"b":2}, but JSON.stringify({b:2,a:1}) is the string {"b":2,"a":1}). Instead, pass the actual value.
typeof x returns "object" for arrays and null as well as non-array objects; you need to handle those three cases separately.
When comparing non-array objects, you need to loop through their properties to compare them.
SO has several questions and answers about doing deep equality checks; probably best to search for those, study them to ensure you understand how they work, and go from there.
Why dont you just JSON stringify both arrays and then compare?
const deepEquals(val1, val2){
let v1 = JSON.stringify(val1);
let v2 = JSON.stringify(val2);
return v1 === v2;
}

delete occurrences of an element if it occurs more than n times javascript

So I have this problem which I have been stuck on but have an answer but not sure exactly why it's working... Please can someone explain why this works?
function deleteNth(arr,n){
var cache = {};
return arr.filter(num => {
cache[num] = (cache[num]||0) + 1; // this is the line i am comfused about!!
return cache[num] <= n;
});
}
deleteNth([1,1,3,3,7,2,2,2,2], 3);
So through the filter function it'll run for each of the elements in the array.
The line you are confused about is setting the cache[num].
In the first iteration, num will be 1, and cache will be equal to {}, so cache[num] will be undefined.
It is setting it to (cache[num] || 0) which in real terms means if cache[num] OR 0. As cache[num] is undefined in the first instance, it'll be 0. It is then adding 1.
so each time the number is hit, it is adding one, and then it will return if the number of instances is below or equal the accepted number, in this case 3.
When it goes above that threshold, it'll be equal to false and now it won't be included as part of the filter.
cache[num]||0 means that if cache[num] doesn't have a key num then use the value 0.
This happens because the value cache[num] can be null in the first occurence
var cache = {}
console.log(cache[1]); // undefined
console.log(cache[1] || 0); // 0

Understanding how javascript evaluates the OR operator

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.

Error comparing Array elements in Google script

I have a problem in one of my scripts for a Google Spreadsheet.
In the script I create two arrays, the first one contains a column from the sheet:
var sheet_data = sheet.getRange('C1:C').getValues(); // for example sheet_data = [[""],["text1"],["text2"],[""],["text3"]]
and the second one is hard-coded:
var sheet_names = [["text1"],["text2"],["text3"]];
The sheet_data contains all elements present in sheet_names and I have a while function that finds one specific element (say text1) in sheet_data:
i = 0;
while (sheet_data[i] != sheet_names[1]) { i++; }
In short, I want to find the cell in the column C that contains a specific string. However the loop containing this condition doesn't work for some reason. The loop keeps going on and on but i never increases. I tried the same with a for loop containing an if statement but the if statement containing the above condition fails too. I assumed there must be something wrong with the condition but if I explicitly check the array elements that should be the same, it works:
if (sheet_data[i] == "text1" && sheet_names[1] == "text1") // this works
Why doesn't the direct comparison of the two array elments work?
This looks more to me as a JavaScript issue (I am not familiar with Google Script flavor but the same logic should apply)
You are trying to sheet_data[i] != sheet_names[1], where both sheet_data[i] and sheet_names[1] are ['text1']. In JS, these are 2 different array objects (not same reference), so they would never equal to each other. (different from Python)
The reason that your second solution works is even tricker: when you do ['test1'] == 'test1', because the 2 elements are of different types, JavaScript will try to convert them to the same type, due to your use of == instead of ===. ['test1']'s stringified version is exactly 'test1', resulting in your second solution working.
See example below:
console.log([] == []) // false, different object reference
console.log(['test'] == ['test']) // false
console.log('test' == 'test') // true, both are primitive
console.log(['test'].toString()) // 'test'
console.log(['test'] == 'test') // true, ['test'] converted to 'test' due to ==
console.log(['test'] === 'test') // false, strict comparison without type conversion
// More amazing JS tricks!
console.log([] == 0) // true
console.log([] == '') // true
console.log('' == 0) // true
console.log('' == false) // true
console.log(false == 0) // true
console.log([] == false) // true
// OOOPS...
console.log({} != true) // true
console.log({} != false) // true
// as you see here, NEVER USE == ! use === instead

Test against emptiness fails if number is 0

For some reason, my boss changed the data I get in my JS, so, if once I received strings, now I can receive strings or numbers (from 0 to n). There was no problem until today, when I discovered the old code blocks when the number to test is exactly 0.
The reason is this code:
if(myObject.getData()) {
...
}
else {
//here's where I go
}
getData() returns strings and numbers BUT when the number is 0, the if test takes it for a Boolean value and the result is always false, while two lines later, inside the curly braces, I need the number 0 to send it to a server.
What's the best way to check if data is not null, not false, not "", not even Boolean, and "preserve" my 0?
You can introduce an OR into your if statement to check whether it's the numeric value 0 using the strict equality operator (===):
var data = myObject.getData();
if ( data || data === 0 )
Some test cases:
data = "" // false
data = false // false
data = undefined // false
data = 0 // true
data = 1 // true
data = "test" // true
Reversing your requirements it appears you want only non-empty strings and numbers. If that assumption is correct you could use typeof and do something like:
var data = myObject.getData();
if((typeof data === 'string' && data !== '') || typeof data === 'number') {
//...
}
else{
//here's where I go
}
This approach has two key benefits:
It is explicit in what the input format should be so therefore is self-documenting.
It guards against any future input type modifications.

Categories