JavaScript: How to match out-of-order arrays - javascript

I'm trying to work out how to match arrays that share the same elements, but not necessarily in the same order.
For example, these two arrays share the same set of elements, even though they're in a different order.
Is there any way to determine whether two arrays contain the same elements?
var search1 = ["barry", "beth", "debbie"];
var search2 = ["beth", "barry", "debbie"];
if (search1 == search2) {
document.write("We've found a match!");
} else {
document.write("Nothing matches");
}
I've got a Codepen of this running at the moment over here: http://codepen.io/realph/pen/grblI

The problem with some of the other solutions is that they are of O(n²) complexity, if they're using a for loop inside of a for loop. That's slow! You don't need to sort either—also slow.
We can speed this up to O(2n) complexity1 by using a simple dictionary. This adds O(2n) storage, but that hardly matters.
JavaScript
var isEqual = function (arr1, arr2) {
if (arr1.length !== arr2.length) {
return false; // no point in wasting time if they are of different lengths
} else {
var holder = {}, i = 0, l = arr2.length;
// holder is our dictionary
arr1.forEach(function (d) {
holder[d] = true; // put each item in arr1 into the dictionary
})
for (; i < l; i++) { // run through the second array
if (!(arr2[i] in holder)) return false;
// if it's not in the dictionary, return false
}
return true; // otherwise, return true
}
}
Test Case
var arr1 = ["barry", "beth", "debbie"],
arr2 = ["beth", "barry", "debbie"];
console.log(isEqual(arr1,arr2));
// returns true
fiddle
Improvement
As Ahruss pointed out, the above function will return true for two arrays that are seemingly equal. For example, [1,1,2,3] and [1,2,2,3] would return true. To overcome this, simply use a counter in the dictionary. This works because !undefined and !0 both return true.
var isReallyEqual = function (arr1, arr2) {
if (arr1.length !== arr2.length) {
return false; // no point in wasting time if they are of different lengths
} else {
var holder = {}, i = 0, l = arr2.length;
// holder is our dictionary
arr1.forEach(function (d) {
holder[d] = (holder[d] || 0) + 1;
// checks whether holder[d] is in the dictionary: holder[d] || 0
// this basically forces a cast to 0 if holder[d] === undefined
// then increments the value
})
for (; i < l; i++) { // run through the second array
if (!holder[arr2[i]]) { // if it's not "in" the dictionary
return false; // return false
// this works because holder[arr2[i]] can be either
// undefined or 0 (or a number > 0)
// if it's not there at all, this will correctly return false
// if it's 0 and there should be another one
// (first array has the element twice, second array has it once)
// it will also return false
} else {
holder[arr2[i]] -= 1; // otherwise decrement the counter
}
}
return true;
// all good, so return true
}
}
Test Case
var arr1 = [1, 1, 2],
arr2 = [1, 2, 2];
isEqual(arr1, arr2); // returns true
isReallyEqual(arr1, arr2); // returns false;
1: It's really O(n+m) complexity, whereby n is the size of the first array and m of the second array. However, in theory, m === n, if the arrays are equal, or the difference is nominal as n -> ∞, so it can be said to be of O(2n) complexity. If you're feeling really pedantic, you can say it's of O(n), or linear, complexity.

you can use this function to compare two arrays
function getMatch(a, b) {
for ( var i = 0; i < a.length; i++ ) {
for ( var e = 0; e < b.length; e++ ) {
if ( a[i] === b[e] ){
return true;
}
}
}
}

Feed your arrays to the following function:
function isArrayEqual(firstArray, secondArray) {
if (firstArray === secondArray) return true;
if (firstArray == null || secondArray == null) return false;
if (firstArray.length != secondArray.length) return false;
// optional - sort the arrays
// firstArray.sort();
// secondArray.sort();
for (var i = 0; i < firstArray.length; ++i) {
if (firstArray[i] !== secondArray[i]) return false;
}
return true;
}
Now you may be thinking, can't I just say arrayOne.sort() and arrayTwo.sort() then compare if arrayOne == arrayTwo? The answer is no you can't in your case. While their contents may be the same, they're not the same object (comparison by reference).

You need to simply sort them, then compare them
function compareArrayItems(array1, array2){
array1 = array1.sort();
array2 = array2.sort();
return array1.equals(array2);
}
fiddle
You can use the equals function provided in How to compare arrays in JavaScript?

Sort them firstly. Secondly, if their length is different, then they're not a match.
After that, iterate one array and test a[i] with b[i], a being the first array, b the second.
var search1 = ["barry", "beth", "debbie"],
search2 = ["beth", "barry", "debbie"];
// If length are different, than we have no match.
if ((search1.length != search2.length) || (search1 == null || search2 == null))
document.write("Nothing matches");
var a = search1.sort(),
b = search2.sort(),
areEqual = true;
for (var i = 0; i < a.length; i++) {
// if any two values from the two arrays are different, than we have no match.
if (a[i] != b[i]) {
areEqual = false;
break; // no need to continue
}
}
document.write(areEqual ? "We've found a match!" : "Nothing matches");

Related

Quickest way to check if 2 arrays contain same values in javascript

Is there a quicker or more efficient way to check that two arrays contain the same values in javascript?
Here is what I'm currently doing to check this. It works, but is lengthy.
var arraysAreDifferent = false;
for (var i = 0; i < array1.length; i++) {
if (!array2.includes(array1[i])) {
arraysAreDifferent = true;
}
}
for (var i = 0; i < array2.length; i++) {
if (!array1.includes(array2[i])) {
arraysAreDifferent = true;
}
}
To reduce computational complexity from O(n ^ 2) to O(n), use Sets instead - Set.has is O(1), but Array.includes is O(n).
Rather than a regular for loop's verbose manual iteration, use .every to check if every item in an array passes a test. Also check that both Set's sizes are the same - if that's done, then if one of the arrays is iterated over, there's no need to iterate over the other (other than for the construction of its Set):
const arr1Set = new Set(array1);
const arr2Set = new Set(array2);
const arraysAreDifferent = (
arr1Set.size === arr2Set.size &&
array1.every(item => arr2Set.has(item))
);
function same(arr1, arr2){
//----if you want to check by length as well
// if(arr1.length != arr2.length){
// return false;
// }
// creating an object with key => arr1 value and value => number of time that value repeat;
let frequencyCounter1 = {};
let frequencyCounter2 = {};
for(let val of arr1){
frequencyCounter1[val] = (frequencyCounter1[val] || 0) + 1;
}
for(let val of arr2){
frequencyCounter2[val] = (frequencyCounter2[val] || 0) + 1;
}
for(let key in frequencyCounter1){
//check if the key is present in arr2 or not
if(!(key in frequencyCounter2)) return false;
//check the number of times the value repetiton is same or not;
if(frequencyCounter2[key]!==frequencyCounter1[key]) return false;
}
return true;
}

Comparing equality of elements in two arrays

I have an assignment where I am supposed to check two arrays (unsorted) with integers, to see if
They have the same length
The first element contains integers and the second has the same values squared, in any order
For example:
test([5,4,1], [1,16,25]) // would return true ..
What I've done so far is first sort the two input arrays, and then compare the length. Once we confirm the length is the same we iterate through each value to make sure they're equal. Keep in mind I haven't gotten to comparing the values to their squared counterpart yet, because my loop is not giving me expected results. Here is the code:
function test(arr1, arr2){
// sort arrays
const arr1Sort = arr1.sort(),
arr2Sort = arr2.sort();
// compare length and then compare values
if(arr1Sort.length === arr2Sort.length) {
for(let i = 0; i < arr1Sort.length; i++) {
if(arr1Sort[i] === arr2Sort[i]) {
return true;
} else {
return false;
}
}
}
}
console.log(test([1,2,3], [1,5,4])); returns true but the array values are different?!
Inside the for, no matter whether the if or else is fulfilled, the function will immediately return true or false on the first iteration - it'll never get past index 0. To start with, return true only after the loop has concluded, and return false if arr1Sort[i] ** 2 !== arr2Sort[i] (to check if the first squared equals the second).
Also, when sorting, make sure to use a callback function to compare each item's difference, because otherwise, .sort will sort lexiographically (eg, [1, 11, 2]):
function comp(arr1, arr2){
// sort arrays
const sortCb = (a, b) => a - b;
const arr1Sort = arr1.sort(sortCb),
arr2Sort = arr2.sort(sortCb);
// compare length and then compare values
if(arr1Sort.length !== arr2Sort.length) {
return false;
}
for(let i = 0; i < arr1Sort.length; i++) {
if(arr1Sort[i] ** 2 !== arr2Sort[i]) {
return false;
}
}
return true;
}
console.log(comp([1,2,3], [1,5,4]));
console.log(comp([5,4,1], [1,16,25]));
You can decrease the computational complexity to O(N) instead of O(N log N) by turning arr2 into an object indexed by the squared number beforehand:
function comp(arr1, arr2){
if (arr1.length !== arr2.length) {
return false;
}
const arr2Obj = arr2.reduce((a, num) => {
a[num] = (a[num] || 0) + 1;
return a;
}, {});
for (let i = 0; i < arr1.length; i++) {
const sq = arr1[i] ** 2;
if (!arr2Obj[sq]) {
return false;
}
arr2Obj[sq]--;
}
return true;
}
console.log(comp([1,2,3], [1,5,4]));
console.log(comp([5,4,1], [1,16,25]));
(if duplicates weren't permitted, this would be a lot easier with a Set instead, but they are, unfortunately)
This should work, no mater the data to compare:
function similar(needle, haystack, exact){
if(needle === haystack){
return true;
}
if(needle instanceof Date && haystack instanceof Date){
return needle.getTime() === haystack.getTime();
}
if(!needle || !haystack || (typeof needle !== 'object' && typeof haystack !== 'object')){
return needle === haystack;
}
if(needle === null || needle === undefined || haystack === null || haystack === undefined || needle.prototype !== haystack.prototype){
return false;
}
var keys = Object.keys(needle);
if(exact && keys.length !== Object.keys(haystack).length){
return false;
}
return keys.every(function(k){
return similar(needle[k], haystack[k]);
});
}
console.log(similar(['a', {cool:'stuff', yes:1}, 7], ['a', {cool:'stuff', yes:1}, 7], true));
// not exact
console.log(similar(['a', {cool:'stuff', yes:1}, 7], ['a', {cool:'stuff', stuff:'more', yes:1}, 7, 'more stuff only at the end for numeric array']));

Create a function to evaluate if all elements in the array are the same

Problem
I'm trying to create a function that evaluates an array and if every element inside the array is the same, it would return true and otherwise false. I don't want it to return true/false for each individual element, just for the entire array.
Attempt 1
This method works, but it returns true/false for each element in the array:
function isUniform(arr){
let first = arr[0];
for (let i = 1; i <arr.length; i++){
if (arr[0] !== arr[i]){
console.log(false);
} else {
console.log(true);
}
}
}
Attempt 2
This method returns true/false, once and then prints true again at the end:
function isUniform(arr){
let first = arr[0];
for (let i = 1; i <arr.length; i++){
if (arr[0] !== arr[i]){
console.log(false);
}
}
console.log(true);
}
If you want to test if something is true for every element of an array, you don't really need to write much — you can use array.every for this and just compare the first element. every() is nice because it will return early if a false condition is found.
var arr1 = [1, 1, 1, 1, 1, 1, 1]
var arr2 = [1, 1, 1, 2, 1, 1, 1]
console.log(arr1.every((n, _, self) => n === self[0]))
console.log(arr2.every((n, _, self) => n === self[0]))
This will return true for an empty array, which may or may not be what you want.
Alternative using the object Set
new Set(arr).size === 1 // This means all the elements are equal.
let isUniform = (arr) => new Set(arr).size === 1;
console.log(isUniform([4,4,4,4,4]));
console.log(isUniform([4,4,4,4,4,5]));
Add a return statement with false and end the function. The return value could be used later.
function isUniform(arr) {
let first = arr[0];
for (let i = 1; i < arr.length; i++) {
if (arr[0] !== arr[i]) {
console.log(false);
return false;
}
}
console.log(true);
return true;
}
For using a return value, you need to return true at the end, too.
Try with Array#every .its Checking all other value is same with first index of array
function isUniform(arr) {
return arr.every(a=> a === arr[0])
}
console.log(isUniform([2,2,2,2]));
console.log(isUniform([4,4,4,4,4,5]));
The problem is that you need to stop once you've found the first false element:
function isUniform(arr){
let first = arr[0];
let uniform = true;
for (let i = 1; i <arr.length; i++){
if (arr[0] !== arr[i]){
uniform = false;
break;
}
}
console.log(uniform);
}

How do I know an array contains all zero(0) in Javascript

I have an array. I need to generate an alert if all the array items are 0.
For example,
if myArray = [0,0,0,0];
then alert('all zero');
else
alert('all are not zero');
Thanks.
You can use either Array.prototype.every or Array.prototype.some.
Array.prototype.every
With every, you are going to check every array position and check it to be zero:
const arr = [0,0,0,0];
const isAllZero = arr.every(item => item === 0);
This has the advantage of being very clear and easy to understand, but it needs to iterate over the whole array to return the result.
Array.prototype.some
If, instead, we inverse the question, and we ask "does this array contain anything different than zero?" then we can use some:
const arr = [0,0,0,0];
const someIsNotZero = arr.some(item => item !== 0);
const isAllZero = !someIsNotZero; // <= this is your result
This has the advantage of not needing to check the whole array, since, as soon it finds a non-zero value, it will instantly return the result.
for loop
If you don't have access to modern JavaScript, you can use a for loop:
var isAllZero = true;
for(i = 0; i < myArray.length; ++i) {
if(myArray[i] !== 0) {
isAllZero = false;
break;
}
}
// `isAllZero` contains your result
RegExp
If you want a non-loop solution, based on the not-working one of #epascarello:
var arr = [0,0,0,"",0],
arrj = arr.join('');
if((/[^0]/).exec(arrj) || arr.length != arrj.length){
alert('all are not zero');
} else {
alert('all zero');
}
This will return "all zero" if the array contains only 0
Using ECMA5 every
function zeroTest(element) {
return element === 0;
}
var array = [0, 0, 0, 0];
var allZeros = array.every(zeroTest);
console.log(allZeros);
array = [0, 0, 0, 1];
allZeros = array.every(zeroTest);
console.log(allZeros);
Use an early return instead of 2, 3 jumps. This will reduce the complexity. Also we can avoid initialisation of a temp variable.
function ifAnyNonZero (array) {
for(var i = 0; i < array.length; ++i) {
if(array[i] !== 0) {
return true;
}
}
return false;
}
Using Math.max when you know for certain that no negative values will be present in the array:
const zeros = [0, 0, 0, 0];
Math.max(...zeros) === 0; // true
No need to loop, simple join and reg expression will work.
var arr = [0,0,0,10,0];
if((/[^0]/).exec(arr.join(""))){
console.log("non zero");
} else {
console.log("I am full of zeros!");
}
Another slow way of doing it, but just for fun.
var arr = [0,0,0,0,10,0,0];
var temp = arr.slice(0).sort();
var isAllZeros = temp[0]===0 && temp[temp.length-1]===0;
you can give a try to this :
var arr = [0,0,0,0,0];
arr = arr.filter(function(n) {return n;});
if(arr.length>0) console.log('Non Zero');
else console.log("All Zero");

Check if each item in an array is identical in JavaScript

I need to test whether each item in an array is identical to each other. For example:
var list = ["l","r","b"]
Should evaluate as false, because each item is not identical. On the other hand this:
var list = ["b", "b", "b"]
Should evaluate as true because they are all identical. What would be the most efficient (in speed/resources) way of achieving this?
In ES5, you could do:
arr.every(function(v, i, a) {
// first item: nothing to compare with (and, single element arrays should return true)
// otherwise: compare current value to previous value
return i === 0 || v === a[i - 1];
});
.every does short-circuit as well.
function identical(array) {
for(var i = 0; i < array.length - 1; i++) {
if(array[i] !== array[i+1]) {
return false;
}
}
return true;
}
You could always do a new Set, and check the length.
var set1 = [...new Set(list)].length === 1;
The one line answer is:
arr.every((val, ind, arr) => val === arr[0]);
You can look into Array.every for more details.
Note:
Array.every is available ES5 onwards.
This method returns true for any condition put on an empty array.
Syntax: arr.every(callback[, thisArg]) or array.every(function(currentValue, index, arr), thisValue)
It does not change the original array
The execution of every() is short-circuited. As soon as every() finds an array element that doesn't match the predicate, it immediately returns false and doesn't iterate over the remaining elements
arr.every(i=>i==arr[0]) //will return true if all items in arr are identical
function matchList(list) {
var listItem = list[0];
for (index in list) {
if(list[index] != listItem {
return false;
}
}
return true;
}
var list = ["b", "b", "b"];
var checkItem = list[0];
var isSame = true;
for (var i = 0; i < list.length; i++) {
if (list[i] != checkItem) {
isSame = false;
break;
}
}
return isSame;
function identical(array) {
// a variable holding standard value
//against this standard value we are examining the array
var standard = array[1];
for (var i = 0; i < array.length; i++) {
if (array[i] !== standard) {
return false;
}
}
return true;
}
identical([1, 1, 1, 1, 1]); //return true
identical(['a', 'a', 'a']); //return true
identical(['a', 'a', 'b'])
function identical(array) {
// a variable holding standard value
//against this standard value we are examining the array
var standard = array[1];
for (var i = 0; i < array.length; i++) {
if (array[i] !== standard) {
return false;
}
}
return true;
}
identical([1, 1, 1, 1, 1]); //return true
identical(['a', 'a', 'a']); //return true
identical(['a', 'a', 'b'])
My suggestion would be to remove duplicates (check out Easiest way to find duplicate values in a JavaScript array), and then check to see if the length == 1. That would mean that all items were the same.
function allEqual(list)
{
if(list.length == 0 || list.length == 1)
{
return true;
}
for (index in list) {
if(list[index] != list[index+1] {
return false;
}
}
return true;
}

Categories

Resources