I needed 2d arrays, so I made a nested array since JavaScript doesn't allow them.
They look like this:
var myArray = [
[1, 0],
[1, 1],
[1, 3],
[2, 4]
]
How can I check if this array includes a specific element (i.e. one of these [0,1] arrays) in vanilla JS?
Here is what I tried, with no success (everything returns false) (EDIT: I included the answers in the snippet):
var myArray = [
[1, 0],
[1, 1],
[1, 3],
[2, 4]
]
var itemTrue = [2, 4];
var itemFalse = [4, 4];
function contains(a, obj) {
var i = a.length;
while (i--) {
if (a[i] === obj) {
return true;
}
}
return false;
}
// EDIT: first answer's solution
function isArrayInArray(x, check) {
for (var i = 0, len = x.length; i < len; i++) {
if (x[i][0] === check[0] && x[i][1] === check[1]) {
return true;
}
}
return false;
}
// EDIT: accepted answer's solution
function isArrayInArray2(x, check) {
var result = x.find(function(ele) {
return (JSON.stringify(ele) === JSON.stringify(check));
})
return result !=null
}
console.log("true :" + myArray.includes(itemTrue));
console.log("false :" + myArray.includes(itemFalse));
console.log("true :" + (myArray.indexOf(itemTrue) != -1));
console.log("false :" + (myArray.indexOf(itemFalse) != -1));
console.log("true :" + contains(myArray, itemTrue));
console.log("false :" + contains(myArray, itemFalse));
// EDIT: first answer's solution
console.log("true :" + isArrayInArray(myArray, itemTrue));
console.log("false :" + isArrayInArray(myArray, itemFalse));
// EDIT: accepted answer's solution
console.log("true :" + isArrayInArray2(myArray, itemTrue));
console.log("false :" + isArrayInArray2(myArray, itemFalse));
It could look like duplicate but I couldn't find a similar question. If it is, feel free to tag it as such.
Short and easy, stringify the array and compare as strings
function isArrayInArray(arr, item){
var item_as_string = JSON.stringify(item);
var contains = arr.some(function(ele){
return JSON.stringify(ele) === item_as_string;
});
return contains;
}
var myArray = [
[1, 0],
[1, 1],
[1, 3],
[2, 4]
]
var item = [1, 0]
console.log(isArrayInArray(myArray, item)); // Print true if found
check some documentation here
A nested array is essentially a 2D array, var x = [[1,2],[3,4]] would be a 2D array since I reference it with 2 index's, eg x[0][1] would be 2.
Onto your question you could use a plain loop to tell if they're included since this isn't supported for complex arrays:
var x = [[1,2],[3,4]];
var check = [1,2];
function isArrayInArray(source, search) {
for (var i = 0, len = source.length; i < len; i++) {
if (source[i][0] === search[0] && source[i][1] === search[1]) {
return true;
}
}
return false;
}
console.log(isArrayInArray(x, check)); // prints true
Update that accounts for any length array
function isArrayInArray(source, search) {
var searchLen = search.length;
for (var i = 0, len = source.length; i < len; i++) {
// skip not same length
if (source[i].length != searchLen) continue;
// compare each element
for (var j = 0; j < searchLen; j++) {
// if a pair doesn't match skip forwards
if (source[i][j] !== search[j]) {
break;
}
return true;
}
}
return false;
}
console.log(isArrayInArray([[1,2,3],[3,4,5]], [1,2,3])); // true
You can't do like that .instance you have to do some thing by your own ..
first you have to do a foreach from your array that you want to search and run 'compareArray' function for each item of your array .
function compareArray( arrA, arrB ){
//check if lengths are different
if(arrA.length !== arrB.length) return false;
for(var i=0;i<arrA.length;i++){
if(arrA[i]!==arrB[i]) return false;
}
return true;
}
Here is an ES6 solution:
myArray.some(
r => r.length == itemTrue.length &&
r.every((value, index) => itemTrue[index] == value)
);
Check the JSFiddle.
Take a look at arrow functions and the methods some and every of the Array object.
The code provided by D. Young's comment that checks for any length array is faulty. It only checks if the first element is the same.
A corrected version of D. Young's comment:
function isArrayInArray(source, search) {
var searchLen = search.length;
for (var i = 0, len = source.length; i < len; i++) {
// skip not same length
if (source[i].length != searchLen) continue;
// compare each element
for (var j = 0; j < searchLen; j++) {
// if a pair doesn't match skip forwards
if (source[i][j] !== search[j]) {
break;
} else if (j == searchLen - 1) {return true}
}
}
return false;
}
For those who are interested in finding an array inside another and get back an index number, here's a modified version of mohamed-ibrahim's answer:
function findArrayInArray(innerArray, outerArray) {
const innerArrayString = JSON.stringify(innerArray);
let index = 0;
const inArray = outerArray.some(function (element) {
index ++;
return JSON.stringify(element) === innerArrayString;
});
if (inArray) {
return index - 1;
} else {
return -1;
}
}
findArrayInArray([1, 2, 3], [[3, .3], [1, 2, 3], [2]]); // 1
findArrayInArray([1, 2, 3], [[[1], 2, 3], [2]]) // -1
This function returns the index of the array you are searching inside the outer array and -1 if not found.
Checkout this CodePen.
Related
I have two arrays that I need to check the difference upon and return the index of that difference.
For example, I currently have two arrays that get updated when the input's value is changed. The newTags array gets updated whenever there is a new tag within the input, such as #testing. I need to compare the newTags array with the oldTags array and return the index of the difference.
I am currently stringifying both arrays and comparing them that way, although it is unable to return the index of the difference.
var newTags = [];
var oldTags = [];
$input.on('keyup', function () {
var newValue = $input.val();
var pattern = /#[a-zA-Z]+/ig;
var valueSearch = newValue.search(pattern);
if (valueSearch >= 0) {
newTags = newValue.match(pattern);
if ((newTags + "") != (oldTags + "")) {
//Need index of difference here
console.log(newTags, oldTags);
}
oldTags = newTags;
}
});
Working example
You can use a filter to find both the different values and indexes at the same time.
JSFiddle: https://jsfiddle.net/k0uxtnkd/
Array.prototype.diff = function(a) {
var source = this;
return this.filter(function(i) {
if (a.indexOf(i) < 0) {
diffIndexes.push(source.indexOf(i));
return true;
} else {
return false;
}
});
};
var diffIndexes = [];
var newTags = ['a','b','c'];
var oldTags = ['c'];
var diffValues = newTags.diff(oldTags);
console.log(diffIndexes); // [0, 1]
console.log(diffValues); // ['a', 'b']
To convert this to a function instead of add it to the array prototype:
JSFiddle: https://jsfiddle.net/k0uxtnkd/1/
function arrayDiff(a, b) {
return a.filter(function(i) {
if (b.indexOf(i) < 0) {
diffIndexes.push(a.indexOf(i));
return true;
} else {
return false;
}
});
};
var diffIndexes = [];
var newTags = ['a','b','c'];
var oldTags = ['c'];
var diffValues = arrayDiff(newTags, oldTags);
console.log(diffIndexes); // [0, 1]
console.log(diffValues); // ['a', 'b']
You don't need to loop through both arrays, you can simply loop through both simultaneously:
var findDivergence = function (a1, a2) {
var result = [], longerLength = a1.length >= a2.length ? a1.length : a2.length;
for (i = 0; i < longerLength; i++){
if (a1[i] !== a2[i]) {
result.push(i);
}
}
return result;
};
console.log(findDivergence(["a","b","c","d","e","f","g","h","i"], ["a","b","d","r","e","q","g"]));
//outputs [2, 3, 5, 7, 8]
This is significantly more efficient than double-looping or using indexOf (both of which will search the second array many more times than necessary). This also handles cases where the same item shows up more than once in a given array, though if one array is longer than the other and the longer one contains an element that is undefined, that index will count as a match.
for(var i=0; i < newTags.length; i++) {
for(var j=0; j < oldTags.length; j++) {
if(newTags[i] === oldTags[j]) {
console.log("match found");
console.log("Match found for value: " + newTags[i] + " at index in oldTags: " + j + );
}
else{
console.log("match not found");
}
}
}
Using 2 loops you can do a quick check, in the if statements add what you want to happen.
Below is a performance comparison of three common methods to perform the task asked in this question.
const arr1 = ['A', 'B', 'C'];
const arr2 = ['A', 'D', 'C', 'E'];
// Filter indexOf
function diffArray1(a1, a2) {
let aDiffs = [];
a1.filter((i) => {
if (a2.indexOf(i) < 0) {
aDiffs.push(a1.indexOf(i));
}
});
return aDiffs;
};
// Loop indexOf
function diffArray2(a1, a2) {
let aDiffs = [];
for (let i=0; i<a1.length; ++i) {
if (a2.indexOf(a1[i]) < 0) {
aDiffs.push(a1.indexOf(a1[i]));
}
}
return aDiffs;
};
// Loop equality
function diffArray3(a1, a2) {
let aDiffs = [];
for (let i=0; i<a1.length; ++i) {
if (a1[i] !== a2[i]) {
aDiffs.push(i);
}
}
return aDiffs;
};
diffArray1(arr2, arr1); // Returns [1, 3]
diffArray2(arr2, arr1); // Returns [1, 3]
diffArray3(arr2, arr1); // Returns [1, 3]
diffArray3() is the fastest in Chrome v102.0.5005.63 (64-bit) on my system (Intel Core i7-7700HQ 32GB RAM). diffArray1() is about 38% slower and diffArray2() is about 22.5% slower. Here's the test suite:
https://jsbench.me/59l42hhpfs/1
Feel free to fork this and add more methods; please leave the URL of the fork in the comment if you do this.
I have two arrays that I need to check the difference upon and return the index of that difference.
For example, I currently have two arrays that get updated when the input's value is changed. The newTags array gets updated whenever there is a new tag within the input, such as #testing. I need to compare the newTags array with the oldTags array and return the index of the difference.
I am currently stringifying both arrays and comparing them that way, although it is unable to return the index of the difference.
var newTags = [];
var oldTags = [];
$input.on('keyup', function () {
var newValue = $input.val();
var pattern = /#[a-zA-Z]+/ig;
var valueSearch = newValue.search(pattern);
if (valueSearch >= 0) {
newTags = newValue.match(pattern);
if ((newTags + "") != (oldTags + "")) {
//Need index of difference here
console.log(newTags, oldTags);
}
oldTags = newTags;
}
});
Working example
You can use a filter to find both the different values and indexes at the same time.
JSFiddle: https://jsfiddle.net/k0uxtnkd/
Array.prototype.diff = function(a) {
var source = this;
return this.filter(function(i) {
if (a.indexOf(i) < 0) {
diffIndexes.push(source.indexOf(i));
return true;
} else {
return false;
}
});
};
var diffIndexes = [];
var newTags = ['a','b','c'];
var oldTags = ['c'];
var diffValues = newTags.diff(oldTags);
console.log(diffIndexes); // [0, 1]
console.log(diffValues); // ['a', 'b']
To convert this to a function instead of add it to the array prototype:
JSFiddle: https://jsfiddle.net/k0uxtnkd/1/
function arrayDiff(a, b) {
return a.filter(function(i) {
if (b.indexOf(i) < 0) {
diffIndexes.push(a.indexOf(i));
return true;
} else {
return false;
}
});
};
var diffIndexes = [];
var newTags = ['a','b','c'];
var oldTags = ['c'];
var diffValues = arrayDiff(newTags, oldTags);
console.log(diffIndexes); // [0, 1]
console.log(diffValues); // ['a', 'b']
You don't need to loop through both arrays, you can simply loop through both simultaneously:
var findDivergence = function (a1, a2) {
var result = [], longerLength = a1.length >= a2.length ? a1.length : a2.length;
for (i = 0; i < longerLength; i++){
if (a1[i] !== a2[i]) {
result.push(i);
}
}
return result;
};
console.log(findDivergence(["a","b","c","d","e","f","g","h","i"], ["a","b","d","r","e","q","g"]));
//outputs [2, 3, 5, 7, 8]
This is significantly more efficient than double-looping or using indexOf (both of which will search the second array many more times than necessary). This also handles cases where the same item shows up more than once in a given array, though if one array is longer than the other and the longer one contains an element that is undefined, that index will count as a match.
for(var i=0; i < newTags.length; i++) {
for(var j=0; j < oldTags.length; j++) {
if(newTags[i] === oldTags[j]) {
console.log("match found");
console.log("Match found for value: " + newTags[i] + " at index in oldTags: " + j + );
}
else{
console.log("match not found");
}
}
}
Using 2 loops you can do a quick check, in the if statements add what you want to happen.
Below is a performance comparison of three common methods to perform the task asked in this question.
const arr1 = ['A', 'B', 'C'];
const arr2 = ['A', 'D', 'C', 'E'];
// Filter indexOf
function diffArray1(a1, a2) {
let aDiffs = [];
a1.filter((i) => {
if (a2.indexOf(i) < 0) {
aDiffs.push(a1.indexOf(i));
}
});
return aDiffs;
};
// Loop indexOf
function diffArray2(a1, a2) {
let aDiffs = [];
for (let i=0; i<a1.length; ++i) {
if (a2.indexOf(a1[i]) < 0) {
aDiffs.push(a1.indexOf(a1[i]));
}
}
return aDiffs;
};
// Loop equality
function diffArray3(a1, a2) {
let aDiffs = [];
for (let i=0; i<a1.length; ++i) {
if (a1[i] !== a2[i]) {
aDiffs.push(i);
}
}
return aDiffs;
};
diffArray1(arr2, arr1); // Returns [1, 3]
diffArray2(arr2, arr1); // Returns [1, 3]
diffArray3(arr2, arr1); // Returns [1, 3]
diffArray3() is the fastest in Chrome v102.0.5005.63 (64-bit) on my system (Intel Core i7-7700HQ 32GB RAM). diffArray1() is about 38% slower and diffArray2() is about 22.5% slower. Here's the test suite:
https://jsbench.me/59l42hhpfs/1
Feel free to fork this and add more methods; please leave the URL of the fork in the comment if you do this.
I tried finding the sum of all numbers of a nested array, but I don't get it to work correctly. This is what I tried:
function arraySum(i) {
sum = 0;
for (a = 0; a < i.length; a++) {
if (typeof i[a] == 'number') {
sum += i[a];
} else if (i[a] instanceof Array) {
sum += arraySum(i[a]);
}
}
return sum;
}
When you try it out with the array [[1,2,3],4,5], it gets 6 as the answer, instead of 15.
Does somebody know where there is a mistake in it?
The problem with your code is that the sum and a variables are global, instead of local. Because of this you get an infinite loop (a from the first entry in the function is reset by the second entry, so the same elements are processed again).
Fix it by adding var to where sum and a are declared to make them local to the function:
function arraySum(i) {
var sum=0; // missing var added
for(var a=0;a<i.length;a++){ // missing var added
if(typeof i[a]=="number"){
sum+=i[a];
}else if(i[a] instanceof Array){
sum+=arraySum(i[a]);
}
}
return sum;
}
Demo: http://jsbin.com/eGaFOLA/2/edit
I know it's late, but they say "is never late" :)
const sumNestedArray = arr => arr.flat(Infinity).reduce((a,b)=> a+b, 0)
const sumNestedArray = arr => arr.flat(Infinity).reduce((a,b)=> a+b, 0)
console.log(sumNestedArray([1,[2], [2, 3, [4]]]))
sumNestedArray([1,[2], [2, 3, [4]]])
For 2018 this solution is clean and functional:
let arr = [[ 1, 2, 3], 4, 5]
arr.flat().reduce((d, i) => d + i)
Documentation for flat and reduce.
Recurse, for example
function arraySum(x) {
var sum = 0, i;
if (typeof x === 'number')
return x;
else if (x instanceof Array)
for (i = 0; i < x.length; ++i)
sum += arraySum(x[i]);
return sum;
}
arraySum([[1,2,3],4,5]); // 15
I didn't optimise this so that it's clear, you may want some more logic before recursion.
The reason yours isn't working is because you need to var both sum and a.
You're missing two var in there. You've implicitly declared sum and a at window scope:
function arraySum(i) {
**var** sum=0;
for(**var** a=0;a<i.length;a++){
if(typeof i[a]=="number"){
sum+=i[a];
}else if(i[a] instanceof Array){
sum+=arraySum(i[a]);
}
}
return sum;
}
First of all why you use 'i' as input to function? we using 'i' to denote running index..
Regarding your question,you want 'a' to be local in your loop so instead of "for(a=0;..." instead write "for(var a=0;"
<html>
<body>
<script>
function NestedArraySummation(arr)
{
var sum=0;
for(var i=0;i<arr.length;i++)
{
if(typeof arr[i]=="number")
sum=sum+arr[i];
else if(arr[i] instanceof Array)
sum=sum+NestedArraySummation(arr[i]);
}
return sum;
}
var MyArray=[1,[2,3],4,10,[1,2]];
var Sum=NestedArraySummation(MyArray);
document.write(Sum);
</script>
</body>
</html>
This can be done with lodash _.flattenDeep and _.sum:
const arr = [[1, 2, 3], 4, 5];
arraySum(arr);
function arraySum(arr) {
var arrFlattens = _.flattenDeep(arr);
// => [1, 2, 3, 4, 5]
console.log(_.sum(arrFlattens));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Here you go:
(My assumption is that you want to parse strings, e.g., '13', into numbers in order include them in the sum. If not, just change isNumber to typeof val === 'number'.
function arraySum(arr) {
let sum = 0;
while (arr.length) {
const val = arr.pop();
const isArray = typeof val === 'object' && val.length !== undefined;
const isNumber = !isArray && !isNaN(sum + parseFloat(val));
if (isArray && val.length) {
sum += arraySum(val);
}
else if (isNumber) {
sum += parseFloat(val);
}
}
return sum;
}
console.log(arraySum([])); //0
console.log(arraySum([1, 1, 1, [3, 4, [8]], [4]])); //22
console.log(arraySum([1, 1, [], {}, 'l', 1, [3, 4, [8]], [4]])); //22
This was posted long ago but it might help others. I did the following and it seems to be working just fine
function countArray (array) {
//iterate through the array
for(let i = 0;i < array.length; i++){
//check if element of array is an array, and if it is, run method flat() to the whole array.
if(Array.isArray(array[i])){
array = array.flat()
}
}
//return the sum of the elements of the array
return array.reduce((a,b) => a + b);
}
from __builtin__ import int
def nestedLists(mylist):
sum = 0
if checkIfAllInt(mylist):
result = addList(mylist)
return result
else:
for value in mylist:
sum = sum + nestedLists(value)
return sum
def addList(listdata):
if(type(listdata) is int):
return listdata
else:
return sum(listdata)
def checkIfAllInt(listdata):
check = True
if(type(listdata) is int):
return check
else:
for value in listdata:
if(not type(value) is int):
check = False
return check
return check
print nestedLists([1,[2,3,[4,5,[6,7]]]])
What's the fastest/best way to compare two arrays and return the difference? Much like array_diff in PHP. Is there an easy function or am I going to have to create one via each()? or a foreach loop?
I know this is an old question, but I thought I would share this little trick.
var diff = $(old_array).not(new_array).get();
diff now contains what was in old_array that is not in new_array
Working demo http://jsfiddle.net/u9xES/
Good link (Jquery Documentation): http://docs.jquery.com/Main_Page {you can search or read APIs here}
Hope this will help you if you are looking to do it in JQuery.
The alert in the end prompts the array of uncommon element Array i.e. difference between 2 array.
Please lemme know if I missed anything, cheers!
Code
var array1 = [1, 2, 3, 4, 5, 6];
var array2 = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var difference = [];
jQuery.grep(array2, function(el) {
if (jQuery.inArray(el, array1) == -1) difference.push(el);
});
alert(" the difference is " + difference); // Changed variable name
use underscore as :
_.difference(array1,array2)
var arrayDiff = function (firstArr, secondArr) {
var i, o = [], fLen = firstArr.length, sLen = secondArr.length, len;
if (fLen > sLen) {
len = sLen;
} else if (fLen < sLen) {
len = fLen;
} else {
len = sLen;
}
for (i=0; i < len; i++) {
if (firstArr[i] !== secondArr[i]) {
o.push({idx: i, elem1: firstArr[i], elem2: secondArr[i]}); //idx: array index
}
}
if (fLen > sLen) { // first > second
for (i=sLen; i< fLen; i++) {
o.push({idx: i, 0: firstArr[i], 1: undefined});
}
} else if (fLen < sLen) {
for (i=fLen; i< sLen; i++) {
o.push({idx: i, 0: undefined, 1: secondArr[i]});
}
}
return o;
};
/** SUBTRACT ARRAYS **/
function subtractarrays(array1, array2){
var difference = [];
for( var i = 0; i < array1.length; i++ ) {
if( $.inArray( array1[i], array2 ) == -1 ) {
difference.push(array1[i]);
}
}
return difference;
}
You can then call the function anywhere in your code.
var I_like = ["love", "sex", "food"];
var she_likes = ["love", "food"];
alert( "what I like and she does't like is: " + subtractarrays( I_like, she_likes ) ); //returns "Naughty"!
This works in all cases and avoids the problems in the methods above. Hope that helps!
In this way you don't need to worry about if the first array is smaller than the second one.
var arr1 = [1, 2, 3, 4, 5, 6,10],
arr2 = [1, 2, 3, 4, 5, 6, 7, 8, 9];
function array_diff(array1, array2){
var difference = $.grep(array1, function(el) { return $.inArray(el,array2) < 0});
return difference.concat($.grep(array2, function(el) { return $.inArray(el,array1) < 0}));;
}
console.log(array_diff(arr1, arr2));
if you also want to compare the order of the answer you can extend the answer to something like this:
Array.prototype.compareTo = function (array2){
var array1 = this;
var difference = [];
$.grep(array2, function(el) {
if ($.inArray(el, array1) == -1) difference.push(el);
});
if( difference.length === 0 ){
var $i = 0;
while($i < array1.length){
if(array1[$i] !== array2[$i]){
return false;
}
$i++;
}
return true;
}
return false;
}
The short version can be like this:
const diff = (a, b) => b.filter((i) => a.indexOf(i) === -1);
result:
diff(['a', 'b'], ['a', 'b', 'c', 'd']);
["c", "d"]
Array operations like this is not jQuery's strongest point. You should consider a library such as Underscorejs, specifically the difference function.
This should work with unsorted arrays, double values and different orders and length, while giving you the filtered values form array1, array2, or both.
function arrayDiff(arr1, arr2) {
var diff = {};
diff.arr1 = arr1.filter(function(value) {
if (arr2.indexOf(value) === -1) {
return value;
}
});
diff.arr2 = arr2.filter(function(value) {
if (arr1.indexOf(value) === -1) {
return value;
}
});
diff.concat = diff.arr1.concat(diff.arr2);
return diff;
};
var firstArray = [1,2,3,4];
var secondArray = [4,6,1,4];
console.log( arrayDiff(firstArray, secondArray) );
console.log( arrayDiff(firstArray, secondArray).arr1 );
// => [ 2, 3 ]
console.log( arrayDiff(firstArray, secondArray).concat );
// => [ 2, 3, 6 ]
I have two arrays and I want to check if every element in arr2 is in arr1. If the value of an element is repeated in arr2, it needs to be in arr1 an equal number of times. What's the best way of doing this?
arr1 = [1, 2, 3, 4]
arr2 = [1, 2]
checkSuperbag(arr1, arr2)
> true //both 1 and 2 are in arr1
arr1 = [1, 2, 3, 4]
arr2 = [1, 2, 5]
checkSuperbag(arr1, arr2)
> false //5 is not in arr1
arr1 = [1, 2, 3]
arr2 = [1, 2, 3, 3]
checkSuperbag(arr1, arr2)
> false //3 is not in arr1 twice
Do you have to support crummy browsers? If not, the every function should make this easy.
If arr1 is a superset of arr2, then each member in arr2 must be present in arr1
var isSuperset = arr2.every(function(val) { return arr1.indexOf(val) >= 0; });
Here's a fiddle
EDIT
So you're defining superset such that for each element in arr2, it occurs in arr1 the same number of times? I think filter will help you do that (grab the shim from the preceding MDN link to support older browsers):
var isSuperset = arr2.every(function (val) {
var numIn1 = arr1.filter(function(el) { return el === val; }).length;
var numIn2 = arr2.filter(function(el) { return el === val; }).length;
return numIn1 === numIn2;
});
Updated Fiddle
END EDIT
If you do want to support older browsers, the MDN link above has a shim you can add, which I reproduce here for your convenience:
if (!Array.prototype.every)
{
Array.prototype.every = function(fun /*, thisp */)
{
"use strict";
if (this == null)
throw new TypeError();
var t = Object(this);
var len = t.length >>> 0;
if (typeof fun != "function")
throw new TypeError();
var thisp = arguments[1];
for (var i = 0; i < len; i++)
{
if (i in t && !fun.call(thisp, t[i], i, t))
return false;
}
return true;
};
}
EDIT
Note that this will be an O(N2) algorithm, so avoid running it on large arrays.
One option is to sort the two arrays, then traverse both, comparing elements. If an element in the sub-bag candidate is not found in the super-bag, the former is not a sub-bag. Sorting is generally O(n*log(n)) and the comparison is O(max(s,t)), where s and t are the array sizes, for a total time complexity of O(m*log(m)), where m=max(s,t).
function superbag(sup, sub) {
sup.sort();
sub.sort();
var i, j;
for (i=0,j=0; i<sup.length && j<sub.length;) {
if (sup[i] < sub[j]) {
++i;
} else if (sup[i] == sub[j]) {
++i; ++j;
} else {
// sub[j] not in sup, so sub not subbag
return false;
}
}
// make sure there are no elements left in sub
return j == sub.length;
}
If the elements in the actual code are integers, you can use a special-purpose integer sorting algorithm (such as radix sort) for an overall O(max(s,t)) time complexity, though if the bags are small, the built-in Array.sort will likely run faster than a custom integer sort.
A solution with potentially lesser time-complexity is to create a bag type. Integer bags are particularly easy. Flip the existing arrays for the bags: create an object or an array with the integers as keys and a repeat count for values. Using an array won't waste space by creating as arrays are sparse in Javascript. You can use bag operations for sub-bag or super-bag checks. For example, subtract the super from the sub candidate and test if the result non-empty. Alternatively, the contains operation should be O(1) (or possibly O(log(n))), so looping over the sub-bag candidate and testing if the super-bag containment exceeds the sub-bag's containment for each sub-bag element should be O(n) or O(n*log(n)).
The following is untested. Implementation of isInt left as an exercise.
function IntBag(from) {
if (from instanceof IntBag) {
return from.clone();
} else if (from instanceof Array) {
for (var i=0; i < from.length) {
this.add(from[i]);
}
} else if (from) {
for (p in from) {
/* don't test from.hasOwnProperty(p); all that matters
is that p and from[p] are ints
*/
if (isInt(p) && isInt(from[p])) {
this.add(p, from[p]);
}
}
}
}
IntBag.prototype=[];
IntBag.prototype.size=0;
IntBag.prototype.clone = function() {
var clone = new IntBag();
this.each(function(i, count) {
clone.add(i, count);
});
return clone;
};
IntBag.prototype.contains = function(i) {
if (i in this) {
return this[i];
}
return 0;
};
IntBag.prototype.add = function(i, count) {
if (!count) {
count = 1;
}
if (i in this) {
this[i] += count;
} else {
this[i] = count;
}
this.size += count;
};
IntBag.prototype.remove = function(i, count) {
if (! i in this) {
return;
}
if (!count) {
count = 1;
}
this[i] -= count;
if (this[i] > 0) {
// element is still in bag
this.size -= count;
} else {
// remove element entirely
this.size -= count + this[i];
delete this[i];
}
};
IntBag.prototype.each = function(f) {
var i;
foreach (i in this) {
f(i, this[i]);
}
};
IntBag.prototype.find = function(p) {
var result = [];
var i;
foreach (i in this.elements) {
if (p(i, this[i])) {
return i;
}
}
return null;
};
IntBag.prototype.sub = function(other) {
other.each(function(i, count) {
this.remove(i, count);
});
return this;
};
IntBag.prototype.union = function(other) {
var union = this.clone();
other.each(function(i, count) {
if (union.contains(i) < count) {
union.add(i, count - union.contains(i));
}
});
return union;
};
IntBag.prototype.intersect = function(other) {
var intersection = new IntBag();
this.each(function (i, count) {
if (other.contains(i)) {
intersection.add(i, Math.min(count, other.contains(i)));
}
});
return intersection;
};
IntBag.prototype.diff = function(other) {
var mine = this.clone();
mine.sub(other);
var others = other.clone();
others.sub(this);
mine.union(others);
return mine;
};
IntBag.prototype.subbag = function(super) {
return this.size <= super.size
&& null !== this.find(
function (i, count) {
return super.contains(i) < this.contains(i);
}));
};
See also "comparing javascript arrays" for an example implementation of a set of objects, should you ever wish to disallow repetition of elements.
No one has posted a recursive function yet and those are always fun. Call it like arr1.containsArray( arr2 ).
Demo: http://jsfiddle.net/ThinkingStiff/X9jed/
Array.prototype.containsArray = function ( array /*, index, last*/ ) {
if( arguments[1] ) {
var index = arguments[1], last = arguments[2];
} else {
var index = 0, last = 0; this.sort(); array.sort();
};
return index == array.length
|| ( last = this.indexOf( array[index], last ) ) > -1
&& this.containsArray( array, ++index, ++last );
};
Using objects (read: hash tables) in stead of sorting should reduce the amortized complexity to O(m+n):
function bagContains(arr1, arr2) {
var o = {}
var result = true;
// Count all the objects in container
for(var i=0; i < arr1.length; i++) {
if(!o[arr1[i]]) {
o[arr1[i]] = 0;
}
o[arr1[i]]++;
}
// Subtract all the objects in containee
// And exit early if possible
for(var i=0; i < arr2.length; i++) {
if(!o[arr2[i]]) {
o[arr2[i]] = 0;
}
if(--o[arr2[i]] < 0) {
result = false;
break;
}
}
return result;
}
console.log(bagContains([1, 2, 3, 4], [1, 3]));
console.log(bagContains([1, 2, 3, 4], [1, 3, 3]));
console.log(bagContains([1, 2, 3, 4], [1, 3, 7]));
Which yields true, false, false.
Found this on github lodash library. This function use built in functions to solve the problem. .includes() , .indexOf() and .every()
var array1 = ['A', 'B', 'C', 'D', 'E'];
var array2 = ['B', 'C', 'E'];
var array3 = ['B', 'C', 'Z'];
var array4 = [];
function arrayContainsArray (superset, subset) {
if (0 === subset.length) {
return false;
}
return subset.every(function (value) {
return (superset.includes(value));
});
}
function arrayContainsArray1 (superset, subset) {
if (0 === subset.length) {
return false;
}
return subset.every(function (value) {
return (superset.indexOf(value) >= 0);
});
}
console.log(arrayContainsArray(array1,array2)); //true
console.log(arrayContainsArray(array1,array3)); //false
console.log(arrayContainsArray(array1,array4)); //false
console.log(arrayContainsArray1(array1,array2)); //true
console.log(arrayContainsArray1(array1,array3)); //false
console.log(arrayContainsArray1(array1,array4)); //false
If arr2 is subset of arr1, then Length of set(arr1 + arr2) == Length of set(arr1)
var arr1 = [1, 'a', 2, 'b', 3];
var arr2 = [1, 2, 3];
Array.from(new Set(arr1)).length == Array.from(new Set(arr1.concat(arr2))).length
Here is my solution:
Array.prototype.containsIds = function (arr_ids) {
var status = true;
var current_arr = this;
arr_ids.forEach(function(id) {
if(!current_arr.includes(parseInt(id))){
status = false;
return false; // exit forEach
}
});
return status;
};
// Examples
[1,2,3].containsIds([1]); // true
[1,2,3].containsIds([2,3]); // true
[1,2,3].containsIds([3,4]); // false
As for another approach you may do as follows;
function checkIn(a,b){
return b.every(function(e){
return e === this.splice(this.indexOf(e),1)[0];
}, a.slice()); // a.slice() is the "this" in the every method
}
var arr1 = [1, 2, 3, 4],
arr2 = [1, 2],
arr3 = [1,2,3,3];
console.log(checkIn(arr1,arr2));
console.log(checkIn(arr1,arr3));
Quick solution here take two arrays if b is longer than it can't be a super set so return false. Then loop through b to see if a contains the element. If so delete it from a and move on if not return false. Worse case scenario is if b is a subset then time will b.length.
function isSuper(a,b){
var l=b.length,i=0,c;
if(l>a.length){return false}
else{
for(i;i<l;i++){
c=a.indexOf(b[i]);
if(c>-1){
a.splice(c,1);
}
else{return false}
}
return true;
}
}
This assumes that inputs will not always be in order and if a is 1,2,3 and b is 3,2,1 it will still return true.
Yet another simple solution is the following:
let a = [1,2,'a',3,'b',4,5]
let b = [1,2,4]
console.log(b.every((i) => a.includes(i)))
Hope it helps