Reputation: 247
I am learning Javascript, and I saw a function on SO for comparing arrays to check if they are same. However, my current function returns false if the two arrays are [string1,string2] & [string2,string1]. Basically, the two positions are interchanged. The code is as follows:
function _compareArrays(arr1,arr2){
var result = arr1 != null && arr2 != null && arr1.length == arr2.length && arr1.every(function(element) {
return arr2.indexOf(element);
});
return result ;
}
However, I want these two arrays to be returned as same. So, I changed .every
to .indexOf()
and it seemed to work. But, I have a doubt, how exactly is the counter getting incremented here to make sure the comparison is being done for every element?
I mean, like, in C++, we do,
for (int i = 0; i < 10; i++)
if (arr1[i] == arr2[i]
cout<<"Elements are same\n";
Here, I have an explicit i++
which increments the counter. How does it happen in the above function?
Thanks!
Upvotes: 2
Views: 4623
Reputation: 306
So the fastest way would be to sort both arrays, then compare each one element by element. This requires 2n * log(n) + n
time rather than n2 time.
function compareArrays(arr1, arr2){
if(arr1.length !== arr2.length) return false;
// implement custom sort if necessary
arr1.sort();
arr2.sort();
// use normal for loop so we can return immediately if not equal
for(let i=0; i<arr1.length; i++){
if(arr1[i] !== arr2[i]) return false;
}
return true;
}
Upvotes: 1
Reputation: 2507
Your current has these issues:
It will return true
for these 2 arrays (I hope that you understand that this is not specific to these 2): [1, 2, 2]
, [1,1,2]
. This problem is why I set indices to undefined
after a match in my solution below.
indexOf
returns -1
for element's it cannot find, and any number >= 0
if it can find the element, -1
is truthy, so if an element cannot be found, your comparison will return true
, and 0
is falsy, so if an element is located in the first index of the second array, your method will return false
(which means the whole thing will become false
, because of every
...). So, you should add a ~
before the result of indexOf
call: ~arr2.indexOf(element)
.
See this
MDN page on the Bitwise Not operator (~
) and how it solves the
indexOf
problem I mentioned.
I also recommend that you take a look at this answer of mine on truthy/falsy values and how they interact with &&
and ||
.
So Try this out (it's mostly your example, except there is no indexOf
used and I have fixed problem #2):
function _compareArrays(arr1,arr2){
if(!(arr1 != null && arr2 != null && arr1.length == arr2.length)) {
return false;
}
/* copy the arrays so that the original arrays are not affected when we set the indices to "undefined" */
arr1 = [].concat(arr1);
arr2 = [].concat(arr2);
return arr1.every(function(element, index) {
return arr2.some(function(e, i) {
return e === element && (arr2[i] = undefined, true);
});
});
}
var x = ["str", "boo", "str"];
var y = ["boo", "str", "str"];
var z = ["abc", "def", "ghi"]
console.log(_compareArrays(x, y));
console.log(_compareArrays(x, z));
console.log(_compareArrays(z, z));
It won't work if the array has any undefined
elements, though.
Upvotes: 1
Reputation: 909
Convert the array into an object instead. Convert array values into keys and their respective count as their value. This is more performant as you iterate over the arrays only once.
function compare(a, b) {
if (a.length !== b.length) {
return false;
}
let set = {};
a.forEach((i) => {
if (set[i] !== undefined) {
set[i]++;
} else {
set[i] = 1;
}
});
let difference = b.every((i) => {
if (set[i] === undefined) {
return false;
} else {
set[i]--;
if (set[i] === 0) {
delete set[i];
}
return true;
}
});
return Object.keys(set) == 0 && difference;
}
The first loop on the first array initialises the the set (object), the second loop on the second array subtracts the count and removes the keys when the count hits 0. If a key is not found or if the set is not empty at the end of the procedure, then the arrays are not similar.
Upvotes: 2