Why this works(JavaScript)? - javascript

I was working on one of my projects and had to check if any of the coordinates in two arrays(of the same length) at the same index are the exact same or not. I know there are few methods to do this but I came across one that started to rise my curiosity. Why does it work?
So here is a syntax -
exports.check = (arr1, arr2) => {
for(var i = arr1.length; i--;) {
if(arr1[i] !== arr2[i])
return true; //If none of the points are the same
}return false; //If some of the points are the same
}
By my knowledge return statement should stop/break the loop and return the first value in any case. True or not. But it does not... Can someone explain what am I missing here?

You are probably confused with the way the if block is appearing. You can avoid brackets if the result after an if check is a one-liner. It does return true only and only when there is not a match.
This:
exports.check = (arr1, arr2) => {
for(var i = arr1.length; i--;) {
if(arr1[i] !== arr2[i])
return true; //If none of the points are the same
}return false; //If some of the points are the same
}
is the same as:
exports.check = (arr1, arr2) => {
for(var i = arr1.length; i--;) {
if(arr1[i] !== arr2[i]) {
return true;
}
}
return false;
}
P.S: The comments in your code are wrong and the code as well. This is just to explain the about the if block

It might be easier to understand if presented thus:
//returns true if arrays differ or false if arrays are same
exports.arraysAreDifferent = (arr1, arr2) =>
{
for(var i = arr1.length; i>=0; i--) {
if(arr1[i] !== arr2[i]){
return true; //if even one pair of array values differ, arrays are different
} else {
//do nothing/check next pair
}
}
return false; //Loop finished without finding difference. Arrays are same
}
The comments were a bit misleading, and the indentation/bracketing/putting return false after the girly bracket that closed the loop might have been a confusing read that made it look like it was "if x then return this else return that" so you may have pondered how would the loop run to completion. It runs because there is no else; if the if test always fails the loop runs through every pair

Related

Fast way to check if a javascript array is binary (contains only 0 and 1)

What is a quick way to determine if an array is only composed of 0's and 1's?
I'm vaguely familiar with a boolean solution but am not away how to implement it. In order to implement is you would have to assign values to the boolean
true = 0
and
false = 1
But how would you implement this if you are given an array such that
array = [1,1,1,1,0,0,0,0]
isArrayBool (){
}
Very very naive solution:
function isArrayBool(array) {
for (var i of array) {
if (i !== 0 && i !== 1) return false;
}
return true;
}
console.log(isArrayBool([1,0,0,0,1])); // true
console.log(isArrayBool([1])); // true
console.log(isArrayBool([2,3,0])); // false
So I threw a few functions together in jsperf to test. The fastest one I found so far is the one below (which is much faster than the for of version):
function isBoolFor(arr) {
for(var i=arr.length-1; i>=0; --i){
if(arr[i] !== 0 && arr[i] !== 1) return false
}
return true
}
Comparison is here
EDIT: I played around with another version that turned out to be quicker:
function isBoolFor(arr) {
for(var i=0; arr[i] === 0 || arr[i] === 1; i++){}
return i === arr.length
}
The key here is that because most of the array you are checking will consist of zeros and ones, you can avoid doing two boolean checks every iteration by using the || instead of the && negative check. It is only a subtle improvement, and could be argued to be no better than the one above in practicality.
UPDATE: So the difference between all the for and while variants is too subtle to declare an overall winner. So in that case I would go for readability. If you want binary use typed arrays!
FINAL UPDATE:
I was curious and wanted to find an even faster version, and it can be done if the array is known to be only numbers. If the array contains only numbers, then you can use a bitwise operator check for either of the values in question. For example:
function isBoolFor(arr) {
const test = ~0x01
for(var i=arr.length-1; i>=0; --i){
if(test & arr[i]){ return false }
}
return true
}
https://jsperf.com/bool-array-test-2/1
As we can see here, the fastest way to do this can be seen here... With a simple for loop, as suggested by user Jaromanda in a comment. This for loop blows other solutions out of the water in terms of speed.
var someArray = [1,0,1,1,1,1,0,0,1,0,1,0,0,1,0,1,0,1,1,1,1,0,1,1,0,1,0];
function simpleForLoop(array){
var numArgs = someArray.length;
for(var loop = 0; loop < numArgs; loop++){
var arg = someArray[loop];
if(arg !== 0 && arg !== 1){ return false; }
}
return true;
}
var isbool = simpleForLoop(someArray);

Update: Unexpected results when using updated 'contains' method. Changes value of foreach 'key'

I start with 2 string arrays:
var ny_students = [......];
var la_student = [.....];
I've got this bit of code that adds to the array:
for (i=0;i<array.length;i++) {
if (ny_students.contains(array[i]["Result"])){
array[i].Class = "Advanced";
}
else{
if (la_students.contains(array[i]["Result"])){
array[i].Class = "General";
}
else{
if (i==0) {
array.splice(i,1);
}
else {
array.splice(i-1,1);
}
i--;
}
}
}
I am getting unexpected results; the 'key' value somehow becomes 'contains'. Here is the 'contains' method definition:
Array.prototype.contains = function ( needle ) {
for (i in this) {
if (this[i] == needle) return true;
}
return false;
}
Adding to the Array.prototype the way you have will make the contains function enumerable and thus appear in the for...in loop
This is why you never use for...in on an array
Alternatively, define contains in such a way that is is not enumerable
Object.defineProperty(Array.prototype, 'contains', {
configurable: true,
value: function ( needle ) {
for (var i = 0; i < this.length; i++) {
if (this[i] == needle) return true;
}
return false;
}
});
The for...in syntax in JS iterates over "iterable" properties of objects, and there is no promise that they'll be returned in order. Sadly enough, the creators of JS didn't think things through and made the "length" property iterable. So we're stuck with using the lame syntax:
for(var i=0; i<arr.length; ++i) { ... }
You don't need your own contains method because arr.indexOf(n) will return -1 if the value n isn't found. So just do if(arr.indexOf(n) !== -1) to check if a value is in the array.
Finally, the array has a concat method which can combine two arrays (not sure if that will be useful to you in that code, but it's worth pointing out). So if you need to check if a value is in one of two arrays, you could just do :
if(arr1.concat(arr2).indexOf(n) != -1) { ... }
Note that the elements of arr2 don't get added to arr1 when you do that - it actually returns a new array which contains the elements of both arrays.

javascript says two values are not equal when they are (using ===)

I want to use JavaScript to determine which class/display color a number of divs(called div1, div2...up through div21) are depending on the values in schedule_array. So if 2 is in schedule_array, I want div2 to be of class clicked and if 3 is not in schedule_array, I want div3 to be of class unclicked. The problem is that my === sign seems to be giving false no matter what for this code:
function setClasses()
{
alert("schedule array is "+schedule_array[3]);
for(var k = 1; k<22; k++)
{
var name = "div" + k;
if(contains(schedule_array, k))
{
document.getElementById(name).className = "clicked";
}
else
{
document.getElementById(name).className = "unclicked";
}
}
}
setClasses();
function contains(a, obj) {
//alert(a[3] + "for function contains");
//alert(a.length);
for (var i = 0; i < a.length; i++) {
document.write(a[i] + "=" + obj);
if (a[i] === obj) {
document.write("true,,,,,,,,");
return true;
}
else
{
document.write("false,,,,,,,,");
}
}
return false;
}
(stole this latter function from http://stackoverflow.com/questions/237104/array-containsobj-in-javascript)
I have no idea why, but the following code's == fails even when I am comparing the same integer to itself. For example with the code below I get output like:
21=21false,,,,,,
As you can see I've already checked to make sure schedule_array exists and has valid numbers. I have also checked to make sure both for loops are running. Finally, I confirmed that in js, even something like "5"==5 should give a true, so even if there is some weird typing going on, that shouldn't affect the outcome.
Question: what is up with this weirdness? What am I doing wrong?
This works for me.
function contains(a, obj) {
for (var i = 0; i < a.length; i++) {
if (a[i] == obj) {
return true;
}
}
return false;
}
alert(contains(['1', 2, 3, 4, 5], 1));
Are you sure that a is an array?
http://jsfiddle.net/kjruk00b/
You are using === which is a equality without conversion (strict equality). This means that, that although the numeric value is the same (equality) the strict equality operator is not coercing the String into a Integer to allow this comparison to happen. Switching to the non-strict equality operator == should solve your problem as it will convert the String into an Integer, allowing the comparison to work as you expected.
It may be worth your while looking at the Javascript truth tables for these 2 operators to get an idea for how they work.

Faster code for checking repeated values in a JS array

var valueArray = ['ABC','DEF','GHI','ABC','JKL','MNO','DEF'];
var flag =false;
for(var i=0; i<valueArray.length; i++)
{
for(var j=0; j<valueArray.length; j++)
{
if(valueArray[j] == valueArray[i] && j != i)
{
flag = true;
break;
}
}
}
if(flag)
alert('same values found');
I am trying to validate one array by checking for duplicate values, i used above code, i don't think its a better way. is there any ways with jquery for this or some good js codes for it.
Not sure about jquery, but performance will be better with just one for loop:
for(var i = 0; i < valueArray.length; i++)
{
if (valueArray.indexOf(valueArray[i], i+1) != -1) {
flag = true;
break;
}
}
jsPerf test: http://jsperf.com/check-for-double-occurences
If you want a fast, compatible, "works everywhere" function that just checks for duplicates and doesn't require any library, consider:
function hasDups(arr) {
// Firstly copy array so don't affect original, then sort
var t = arr.slice().sort();
// If adjacent members have the same value, return true
for (var i=1, iLen=t.length; i<iLen; i++) {
if (t[i] === t[i-1]) return true;
}
return false;
}
console.log(hasDups(['abc','dvf','abc'])); // true
However you might want something a little more functional, e.g. that you can provide a compare function to so that, say, 'abc' == 'ABC' or '5' == 5.
Or if you want to use new features and avoid the copy and sort, consider:
function hasDups2(arr) {
var obj = {};
return arr.some(function(v){
if (obj.hasOwnProperty(v)) return true;
obj[v] = '';
});
}
The same strategy can be applied to the first as well and avoid ES5's some.
Note that both the above are only really suitable for comparing primitive values, though the first is better for that. If you want a reliable function to look for duplicate objects, that requires a bit more work.
Use jquery.unique() and compare the array size. If the size of the resultant array is not the same then return false.
Doc for jquery.unique()

In Javascript, how do I check if an array has duplicate values?

Possible Duplicate:
Easiest way to find duplicate values in a javascript array
How do I check if an array has duplicate values?
If some elements in the array are the same, then return true. Otherwise, return false.
['hello','goodbye','hey'] //return false because no duplicates exist
['hello','goodbye','hello'] // return true because duplicates exist
Notice I don't care about finding the duplication, only want Boolean result whether arrays contains duplications.
If you have an ES2015 environment (as of this writing: io.js, IE11, Chrome, Firefox, WebKit nightly), then the following will work, and will be fast (viz. O(n)):
function hasDuplicates(array) {
return (new Set(array)).size !== array.length;
}
If you only need string values in the array, the following will work:
function hasDuplicates(array) {
var valuesSoFar = Object.create(null);
for (var i = 0; i < array.length; ++i) {
var value = array[i];
if (value in valuesSoFar) {
return true;
}
valuesSoFar[value] = true;
}
return false;
}
We use a "hash table" valuesSoFar whose keys are the values we've seen in the array so far. We do a lookup using in to see if that value has been spotted already; if so, we bail out of the loop and return true.
If you need a function that works for more than just string values, the following will work, but isn't as performant; it's O(n2) instead of O(n).
function hasDuplicates(array) {
var valuesSoFar = [];
for (var i = 0; i < array.length; ++i) {
var value = array[i];
if (valuesSoFar.indexOf(value) !== -1) {
return true;
}
valuesSoFar.push(value);
}
return false;
}
The difference is simply that we use an array instead of a hash table for valuesSoFar, since JavaScript "hash tables" (i.e. objects) only have string keys. This means we lose the O(1) lookup time of in, instead getting an O(n) lookup time of indexOf.
You could use SET to remove duplicates and compare, If you copy the array into a set it will remove any duplicates. Then simply compare the length of the array to the size of the set.
function hasDuplicates(a) {
const noDups = new Set(a);
return a.length !== noDups.size;
}
One line solutions with ES6
const arr1 = ['hello','goodbye','hey']
const arr2 = ['hello','goodbye','hello']
const hasDuplicates = (arr) => arr.length !== new Set(arr).size;
console.log(hasDuplicates(arr1)) //return false because no duplicates exist
console.log(hasDuplicates(arr2)) //return true because duplicates exist
const s1 = ['hello','goodbye','hey'].some((e, i, arr) => arr.indexOf(e) !== i)
const s2 = ['hello','goodbye','hello'].some((e, i, arr) => arr.indexOf(e) !== i);
console.log(s1) //return false because no duplicates exist
console.log(s2) //return true because duplicates exist
Another approach (also for object/array elements within the array1) could be2:
function chkDuplicates(arr,justCheck){
var len = arr.length, tmp = {}, arrtmp = arr.slice(), dupes = [];
arrtmp.sort();
while(len--){
var val = arrtmp[len];
if (/nul|nan|infini/i.test(String(val))){
val = String(val);
}
if (tmp[JSON.stringify(val)]){
if (justCheck) {return true;}
dupes.push(val);
}
tmp[JSON.stringify(val)] = true;
}
return justCheck ? false : dupes.length ? dupes : null;
}
//usages
chkDuplicates([1,2,3,4,5],true); //=> false
chkDuplicates([1,2,3,4,5,9,10,5,1,2],true); //=> true
chkDuplicates([{a:1,b:2},1,2,3,4,{a:1,b:2},[1,2,3]],true); //=> true
chkDuplicates([null,1,2,3,4,{a:1,b:2},NaN],true); //=> false
chkDuplicates([1,2,3,4,5,1,2]); //=> [1,2]
chkDuplicates([1,2,3,4,5]); //=> null
See also...
1 needs a browser that supports JSON, or a JSON library if not.
2 edit: function can now be used for simple check or to return an array of duplicate values
You can take benefit of indexOf and lastIndexOf. if both indexes are not same, you have duplicate.
function containsDuplicates(a) {
for (let i = 0; i < a.length; i++) {
if (a.indexOf(a[i]) !== a.lastIndexOf(a[i])) {
return true
}
}
return false
}
If you are dealing with simple values, you can use array.some() and indexOf()
for example let's say vals is ["b", "a", "a", "c"]
const allUnique = !vals.some((v, i) => vals.indexOf(v) < i);
some() will return true if any expression returns true. Here we'll iterate values (from the index 0) and call the indexOf() that will return the index of the first occurrence of given item (or -1 if not in the array). If its id is smaller that the current one, there must be at least one same value before it. thus iteration 3 will return true as "a" (at index 2) is first found at index 1.
is just simple, you can use the Array.prototype.every function
function isUnique(arr) {
const isAllUniqueItems = input.every((value, index, arr) => {
return arr.indexOf(value) === index; //check if any duplicate value is in other index
});
return isAllUniqueItems;
}
One nice thing about solutions that use Set is O(1) performance on looking up existing items in a list, rather than having to loop back over it.
One nice thing about solutions that use Some is short-circuiting when the duplicate is found early, so you don't have to continue evaluating the rest of the array when the condition is already met.
One solution that combines both is to incrementally build a set, early terminate if the current element exists in the set, otherwise add it and move on to the next element.
const hasDuplicates = (arr) => {
let set = new Set()
return arr.some(el => {
if (set.has(el)) return true
set.add(el)
})
}
hasDuplicates(["a","b","b"]) // true
hasDuplicates(["a","b","c"]) // false
According to JSBench.me, should preform pretty well for the varried use cases. The set size approach is fastest with no dupes, and checking some + indexOf is fatest with a very early dupe, but this solution performs well in both scenarios, making it a good all-around implementation.
function hasAllUniqueChars( s ){
for(let c=0; c<s.length; c++){
for(let d=c+1; d<s.length; d++){
if((s[c]==s[d])){
return false;
}
}
}
return true;
}

Categories

Resources