I am learning Javascript, and I saw a function on SO for paring 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 _pareArrays(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 parison 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!
I am learning Javascript, and I saw a function on SO for paring 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 _pareArrays(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 parison 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!
indexOf
does not take a function as an argument in any documentation I've ever read - So, I changed .every to .indexOf()
when you have a flat tyre, do you replace the wheel with a banana?
– Jaromanda X
Commented
Dec 6, 2017 at 3:56
_pareArrays
method you've defined always returns -1. As for how the every
method iterates without explicitly incrementing a counter: It's a function on the Array prototype that does the itteration automatically. developer.mozilla/en-US/docs/Web/JavaScript/Reference/…
– nipuna-g
Commented
Dec 6, 2017 at 4:02
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 pare(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.
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 parison 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 bee 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 remend 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 _pareArrays(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(_pareArrays(x, y));
console.log(_pareArrays(x, z));
console.log(_pareArrays(z, z));
It won't work if the array has any undefined
elements, though.
So the fastest way would be to sort both arrays, then pare each one element by element. This requires 2n * log(n) + n
time rather than n2 time.
function pareArrays(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;
}