Related
I have a target array ["apple","banana","orange"], and I want to check if other arrays contain any one of the target array elements.
For example:
["apple","grape"] //returns true;
["apple","banana","pineapple"] //returns true;
["grape", "pineapple"] //returns false;
How can I do it in JavaScript?
Vanilla JS
ES2016:
const found = arr1.some(r=> arr2.includes(r))
ES6:
const found = arr1.some(r=> arr2.indexOf(r) >= 0)
How it works
some(..) checks each element of the array against a test function and returns true if any element of the array passes the test function, otherwise, it returns false. indexOf(..) >= 0 and includes(..) both return true if the given argument is present in the array.
vanilla js
/**
* #description determine if an array contains one or more items from another array.
* #param {array} haystack the array to search.
* #param {array} arr the array providing items to check for in the haystack.
* #return {boolean} true|false if haystack contains at least one item from arr.
*/
var findOne = function (haystack, arr) {
return arr.some(function (v) {
return haystack.indexOf(v) >= 0;
});
};
As noted by #loganfsmyth you can shorten it in ES2016 to
/**
* #description determine if an array contains one or more items from another array.
* #param {array} haystack the array to search.
* #param {array} arr the array providing items to check for in the haystack.
* #return {boolean} true|false if haystack contains at least one item from arr.
*/
const findOne = (haystack, arr) => {
return arr.some(v => haystack.includes(v));
};
or simply as arr.some(v => haystack.includes(v));
If you want to determine if the array has all the items from the other array, replace some() to every()
or as arr.every(v => haystack.includes(v));
ES6 solution:
let arr1 = [1, 2, 3];
let arr2 = [2, 3];
let isFounded = arr1.some( ai => arr2.includes(ai) );
Unlike of it: Must contains all values.
let allFounded = arr2.every( ai => arr1.includes(ai) );
Hope, will be helpful.
If you're not opposed to using a libray, http://underscorejs.org/ has an intersection method, which can simplify this:
var _ = require('underscore');
var target = [ 'apple', 'orange', 'banana'];
var fruit2 = [ 'apple', 'orange', 'mango'];
var fruit3 = [ 'mango', 'lemon', 'pineapple'];
var fruit4 = [ 'orange', 'lemon', 'grapes'];
console.log(_.intersection(target, fruit2)); //returns [apple, orange]
console.log(_.intersection(target, fruit3)); //returns []
console.log(_.intersection(target, fruit4)); //returns [orange]
The intersection function will return a new array with the items that it matched and if not matches it returns empty array.
ES6 (fastest)
const a = ['a', 'b', 'c'];
const b = ['c', 'a', 'd'];
a.some(v=> b.indexOf(v) !== -1)
ES2016
const a = ['a', 'b', 'c'];
const b = ['c', 'a', 'd'];
a.some(v => b.includes(v));
Underscore
const a = ['a', 'b', 'c'];
const b = ['c', 'a', 'd'];
_.intersection(a, b)
DEMO: https://jsfiddle.net/r257wuv5/
jsPerf: https://jsperf.com/array-contains-any-element-of-another-array
If you don't need type coercion (because of the use of indexOf), you could try something like the following:
var arr = [1, 2, 3];
var check = [3, 4];
var found = false;
for (var i = 0; i < check.length; i++) {
if (arr.indexOf(check[i]) > -1) {
found = true;
break;
}
}
console.log(found);
Where arr contains the target items. At the end, found will show if the second array had at least one match against the target.
Of course, you can swap out numbers for anything you want to use - strings are fine, like your example.
And in my specific example, the result should be true because the second array's 3 exists in the target.
UPDATE:
Here's how I'd organize it into a function (with some minor changes from before):
var anyMatchInArray = (function () {
"use strict";
var targetArray, func;
targetArray = ["apple", "banana", "orange"];
func = function (checkerArray) {
var found = false;
for (var i = 0, j = checkerArray.length; !found && i < j; i++) {
if (targetArray.indexOf(checkerArray[i]) > -1) {
found = true;
}
}
return found;
};
return func;
}());
DEMO: http://jsfiddle.net/u8Bzt/
In this case, the function could be modified to have targetArray be passed in as an argument instead of hardcoded in the closure.
UPDATE2:
While my solution above may work and be (hopefully more) readable, I believe the "better" way to handle the concept I described is to do something a little differently. The "problem" with the above solution is that the indexOf inside the loop causes the target array to be looped over completely for every item in the other array. This can easily be "fixed" by using a "lookup" (a map...a JavaScript object literal). This allows two simple loops, over each array. Here's an example:
var anyMatchInArray = function (target, toMatch) {
"use strict";
var found, targetMap, i, j, cur;
found = false;
targetMap = {};
// Put all values in the `target` array into a map, where
// the keys are the values from the array
for (i = 0, j = target.length; i < j; i++) {
cur = target[i];
targetMap[cur] = true;
}
// Loop over all items in the `toMatch` array and see if any of
// their values are in the map from before
for (i = 0, j = toMatch.length; !found && (i < j); i++) {
cur = toMatch[i];
found = !!targetMap[cur];
// If found, `targetMap[cur]` will return true, otherwise it
// will return `undefined`...that's what the `!!` is for
}
return found;
};
DEMO: http://jsfiddle.net/5Lv9v/
The downside to this solution is that only numbers and strings (and booleans) can be used (correctly), because the values are (implicitly) converted to strings and set as the keys to the lookup map. This isn't exactly good/possible/easily done for non-literal values.
Using filter/indexOf:
function containsAny(source,target)
{
var result = source.filter(function(item){ return target.indexOf(item) > -1});
return (result.length > 0);
}
//results
var fruits = ["apple","banana","orange"];
console.log(containsAny(fruits,["apple","grape"]));
console.log(containsAny(fruits,["apple","banana","pineapple"]));
console.log(containsAny(fruits,["grape", "pineapple"]));
You could use lodash and do:
_.intersection(originalTarget, arrayToCheck).length > 0
Set intersection is done on both collections producing an array of identical elements.
const areCommonElements = (arr1, arr2) => {
const arr2Set = new Set(arr2);
return arr1.some(el => arr2Set.has(el));
};
Or you can even have a better performance if you first find out which of these two arrays is longer and making Set out for the longest array, while applying some method on the shortest one:
const areCommonElements = (arr1, arr2) => {
const [shortArr, longArr] = (arr1.length < arr2.length) ? [arr1, arr2] : [arr2, arr1];
const longArrSet = new Set(longArr);
return shortArr.some(el => longArrSet.has(el));
};
I wrote 3 solutions. Essentially they do the same. They return true as soon as they get true. I wrote the 3 solutions just for showing 3 different way to do things. Now, it depends what you like more. You can use performance.now() to check the performance of one solution or the other. In my solutions I'm also checking which array is the biggest and which one is the smallest to make the operations more efficient.
The 3rd solution may not be the cutest but is efficient. I decided to add it because in some coding interviews you are not allowed to use built-in methods.
Lastly, sure...we can come up with a solution with 2 NESTED for loops (the brute force way) but you want to avoid that because the time complexity is bad O(n^2).
Note:
instead of using .includes() like some other people did, you can use
.indexOf(). if you do just check if the value is bigger than 0. If
the value doesn't exist will give you -1. if it does exist, it will give you
greater than 0.
indexOf() vs includes()
Which one has better performance? indexOf() for a little bit, but includes is more readable in my opinion.
If I'm not mistaken .includes() and indexOf() use loops behind the scene, so you will be at O(n^2) when using them with .some().
USING loop
const compareArraysWithIncludes = (arr1, arr2) => {
const [smallArray, bigArray] =
arr1.length < arr2.length ? [arr1, arr2] : [arr2, arr1];
for (let i = 0; i < smallArray.length; i++) {
return bigArray.includes(smallArray[i]);
}
return false;
};
USING .some()
const compareArraysWithSome = (arr1, arr2) => {
const [smallArray, bigArray] =
arr1.length < arr2.length ? [arr1, arr2] : [arr2, arr1];
return smallArray.some(c => bigArray.includes(c));
};
USING MAPS Time complexity O(2n)=>O(n)
const compararArraysUsingObjs = (arr1, arr2) => {
const map = {};
const [smallArray, bigArray] =
arr1.length < arr2.length ? [arr1, arr2] : [arr2, arr1];
for (let i = 0; i < smallArray.length; i++) {
if (!map[smallArray[i]]) {
map[smallArray[i]] = true;
}
}
for (let i = 0; i < bigArray.length; i++) {
if (map[bigArray[i]]) {
return true;
}
}
return false;
};
Code in my:
stackblitz
I'm not an expert in performance nor BigO so if something that I said is wrong let me know.
You can use a nested Array.prototype.some call. This has the benefit that it will bail at the first match instead of other solutions that will run through the full nested loop.
eg.
var arr = [1, 2, 3];
var match = [2, 4];
var hasMatch = arr.some(a => match.some(m => a === m));
I found this short and sweet syntax to match all or some elements between two arrays. For example
// OR operation. find if any of array2 elements exists in array1. This will return as soon as there is a first match as some method breaks when function returns TRUE
let array1 = ['a', 'b', 'c', 'd', 'e'], array2 = ['a', 'b'];
console.log(array2.some(ele => array1.includes(ele)));
// prints TRUE
// AND operation. find if all of array2 elements exists in array1. This will return as soon as there is a no first match as some method breaks when function returns TRUE
let array1 = ['a', 'b', 'c', 'd', 'e'], array2 = ['a', 'x'];
console.log(!array2.some(ele => !array1.includes(ele)));
// prints FALSE
Hope that helps someone in future!
Just one more solution
var a1 = [1, 2, 3, 4, 5]
var a2 = [2, 4]
Check if a1 contain all element of a2
var result = a1.filter(e => a2.indexOf(e) !== -1).length === a2.length
console.log(result)
What about using a combination of some/findIndex and indexOf?
So something like this:
var array1 = ["apple","banana","orange"];
var array2 = ["grape", "pineapple"];
var found = array1.some(function(v) { return array2.indexOf(v) != -1; });
To make it more readable you could add this functionality to the Array object itself.
Array.prototype.indexOfAny = function (array) {
return this.findIndex(function(v) { return array.indexOf(v) != -1; });
}
Array.prototype.containsAny = function (array) {
return this.indexOfAny(array) != -1;
}
Note: If you'd want to do something with a predicate you could replace the inner indexOf with another findIndex and a predicate
Here is an interesting case I thought I should share.
Let's say that you have an array of objects and an array of selected filters.
let arr = [
{ id: 'x', tags: ['foo'] },
{ id: 'y', tags: ['foo', 'bar'] },
{ id: 'z', tags: ['baz'] }
];
const filters = ['foo'];
To apply the selected filters to this structure we can
if (filters.length > 0)
arr = arr.filter(obj =>
obj.tags.some(tag => filters.includes(tag))
);
// [
// { id: 'x', tags: ['foo'] },
// { id: 'y', tags: ['foo', 'bar'] }
// ]
Good perfomance solution:
We should transform one of arrays to object.
const contains = (arr1, mainObj) => arr1.some(el => el in mainObj);
const includes = (arr1, mainObj) => arr1.every(el => el in mainObj);
Usage:
const mainList = ["apple", "banana", "orange"];
// We make object from array, you can use your solution to make it
const main = Object.fromEntries(mainList.map(key => [key, true]));
contains(["apple","grape"], main) // => true
contains(["apple","banana","pineapple"], main) // => true
contains(["grape", "pineapple"], main) // => false
includes(["apple", "grape"], main) // => false
includes(["banana", "apple"], main) // => true
you can face with some disadvantage of checking by in operator (eg 'toString' in {} // => true), so you can change solution to obj[key] checker
Adding to Array Prototype
Disclaimer: Many would strongly advise against this. The only time it'd really be a problem was if a library added a prototype function with the same name (that behaved differently) or something like that.
Code:
Array.prototype.containsAny = function(arr) {
return this.some(
(v) => (arr.indexOf(v) >= 0)
)
}
Without using big arrow functions:
Array.prototype.containsAny = function(arr) {
return this.some(function (v) {
return arr.indexOf(v) >= 0
})
}
Usage
var a = ["a","b"]
console.log(a.containsAny(["b","z"])) // Outputs true
console.log(a.containsAny(["z"])) // Outputs false
My solution applies Array.prototype.some() and Array.prototype.includes() array helpers which do their job pretty efficient as well
ES6
const originalFruits = ["apple","banana","orange"];
const fruits1 = ["apple","banana","pineapple"];
const fruits2 = ["grape", "pineapple"];
const commonFruits = (myFruitsArr, otherFruitsArr) => {
return myFruitsArr.some(fruit => otherFruitsArr.includes(fruit))
}
console.log(commonFruits(originalFruits, fruits1)) //returns true;
console.log(commonFruits(originalFruits, fruits2)) //returns false;
When I looked at your answers, I could not find the answer I wanted.
I did something myself and I want to share this with you.
It will be true only if the words entered (array) are correct.
function contains(a,b) {
let counter = 0;
for(var i = 0; i < b.length; i++) {;
if(a.includes(b[i])) counter++;
}
if(counter === b.length) return true;
return false;
}
let main_array = ['foo','bar','baz'];
let sub_array_a = ['foo','foobar'];
let sub_array_b = ['foo','bar'];
console.log(contains(main_array, sub_array_a)); // returns false
console.log(contains(main_array,sub_array_b )); // returns true
Array .filter() with a nested call to .find() will return all elements in the first array that are members of the second array. Check the length of the returned array to determine if any of the second array were in the first array.
getCommonItems(firstArray, secondArray) {
return firstArray.filter((firstArrayItem) => {
return secondArray.find((secondArrayItem) => {
return firstArrayItem === secondArrayItem;
});
});
}
It can be done by simply iterating across the main array and check whether other array contains any of the target element or not.
Try this:
function Check(A) {
var myarr = ["apple", "banana", "orange"];
var i, j;
var totalmatches = 0;
for (i = 0; i < myarr.length; i++) {
for (j = 0; j < A.length; ++j) {
if (myarr[i] == A[j]) {
totalmatches++;
}
}
}
if (totalmatches > 0) {
return true;
} else {
return false;
}
}
var fruits1 = new Array("apple", "grape");
alert(Check(fruits1));
var fruits2 = new Array("apple", "banana", "pineapple");
alert(Check(fruits2));
var fruits3 = new Array("grape", "pineapple");
alert(Check(fruits3));
DEMO at JSFIDDLE
Not sure how efficient this might be in terms of performance, but this is what I use using array destructuring to keep everything nice and short:
const shareElements = (arr1, arr2) => {
const typeArr = [...arr1, ...arr2]
const typeSet = new Set(typeArr)
return typeArr.length > typeSet.size
}
Since sets cannot have duplicate elements while arrays can, combining both input arrays, converting it to a set, and comparing the set size and array length would tell you if they share any elements.
With underscorejs
var a1 = [1,2,3];
var a2 = [1,2];
_.every(a1, function(e){ return _.include(a2, e); } ); //=> false
_.every(a2, function(e){ return _.include(a1, e); } ); //=> true
Vanilla JS with partial matching & case insensitive
The problem with some previous approaches is that they require an exact match of every word. But, What if you want to provide results for partial matches?
function search(arrayToSearch, wordsToSearch) {
arrayToSearch.filter(v =>
wordsToSearch.every(w =>
v.toLowerCase().split(" ").
reduce((isIn, h) => isIn || String(h).indexOf(w) >= 0, false)
)
)
}
//Usage
var myArray = ["Attach tag", "Attaching tags", "Blah blah blah"];
var searchText = "Tag attach";
var searchArr = searchText.toLowerCase().split(" "); //["tag", "attach"]
var matches = search(myArray, searchArr);
//Will return
//["Attach tag", "Attaching tags"]
This is useful when you want to provide a search box where users type words and the results can have those words in any order, position and case.
Update #Paul Grimshaw answer, use includes insteed of indexOf for more readable
let found = arr1.some(r=> arr2.indexOf(r) >= 0)
let found = arr1.some(r=> arr2.includes(r))
A short way of writing this:
const found = arr1.some(arr2.includes)
I came up with a solution in node using underscore js like this:
var checkRole = _.intersection(['A','B'], ['A','B','C']);
if(!_.isEmpty(checkRole)) {
next();
}
You are looking for intersection between the two arrays. And you have two major intersection types: 'every' and 'some'. Let me give you good examples:
EVERY
let brands1 = ['Ford', 'Kia', 'VW', 'Audi'];
let brands2 = ['Audi', 'Kia'];
// Find 'every' brand intersection.
// Meaning all elements inside 'brands2' must be present in 'brands1':
let intersectionEvery = brands2.every( brand => brands1.includes(brand) );
if (intersectionEvery) {
const differenceList = brands1.filter(brand => !brands2.includes(brand));
console.log('difference list:', differenceList);
const commonList = brands1.filter(brand => brands2.includes(brand));
console.log('common list:', commonList);
}
If condition is not met (like if you put 'Mercedes' in brands2) then 'intersectionEvery' won't be satisfied - will be bool false.
If condition is met it will log ["Ford", "VW"] as difference and ["Kia", "Audi"] as common list.
Sandbox: https://jsfiddle.net/bqmg14t6/
SOME
let brands1 = ['Ford', 'Kia', 'VW', 'Audi'];
let brands2 = ['Audi', 'Kia', 'Mercedes', 'Land Rover'];
// Find 'some' brand intersection.
// Meaning some elements inside 'brands2' must be also present in 'brands1':
let intersectionSome = brands2.some( brand => brands1.includes(brand) );
if (intersectionSome) {
const differenceList = brands1.filter(brand => !brands2.includes(brand));
console.log('difference list:', differenceList);
const commonList = brands1.filter(brand => brands2.includes(brand));
console.log('common list:', commonList);
}
Here we are looking for some common brands, not necessarily all.
It will log ["Ford", "VW"] as difference and ["Kia", "Audi"] as common brands.
Sandbox: https://jsfiddle.net/zkq9j3Lh/
Personally, I would use the following function:
var arrayContains = function(array, toMatch) {
var arrayAsString = array.toString();
return (arrayAsString.indexOf(','+toMatch+',') >-1);
}
The "toString()" method will always use commas to separate the values. Will only really work with primitive types.
console.log("searching Array: "+finding_array);
console.log("searching in:"+reference_array);
var check_match_counter = 0;
for (var j = finding_array.length - 1; j >= 0; j--)
{
if(reference_array.indexOf(finding_array[j]) > 0)
{
check_match_counter = check_match_counter + 1;
}
}
var match = (check_match_counter > 0) ? true : false;
console.log("Final result:"+match);
Given an array of words, write a function that returns an array of the words that occur an even number of times.
function even(["hello", "hi", "hello", "elephant", "hi"]);
That output should be:
["hello", "hi"]
This has been a toy problem I have been struggling with recently. I have solved similar problems counting and returning the number of occurrences of elements in an array but am having trouble taking that logic and applying it to this problem.
This is what I have tried so far, but have hit a wall when trying to output just the even occurrences:
function even(collection) {
var results = [];
for(var i = 0; i < collection.length; i++){
var value = collection[i];
if(results[value]){
results[value] = results[value] + 1;
}else{
results[value] = 1;
}
}
return results;
}
You can use reduce to get an actual count of the words, then simply return an array of the ones that have an even count:
function even(wordsArr) {
//Object of words and counts
var wordCounts = wordsArr.reduce(function(counts, word) {
if (!counts.hasOwnProperty(word)) {
counts[word] = 0;
}
counts[word]++;
return counts;
}, {});
//Now filter that out and return
return Object.keys(wordCounts).filter(function(word) {
return wordCounts[word] % 2 === 0
});
}
even(["hello", "hi", "hello", "elephant", "hi"]); //["hello", "hi"]
var arr = ["hello", "hi", "hello", "elephant", "hi"];
function onlyEvens( arr )
{
var countObj = {};
for( var i = 0; i < arr.length; i++ )
{
var item = arr[i];
if( countObj[ item ] !== undefined )
countObj[item]++;
else
countObj[item] = 1;
}//for()
var filteredArray = [];
for(var key in countObj )
{
if( countObj[key] % 2 == 0 )
filteredArray.push( key );
}
return filteredArray;
}//onlyEvens()
console.log( onlyEvens( arr ) );
Issues in your code:
you use collection instead of words
you cannot access array the associative way. You must declare it as object:
results[value]
you return result variable, but it is undeclared.
return result;
results only contains the occurrences of every word. There miss the code that calculates if the occurrences of a word are odd or even.
fixed code:
function even(words) { // <<< in your code was collection
var results = {};
for(var i = 0; i < words.length; i++){
var value = words[i];
if(results[value]){
results[value] = results[value] + 1;
}else{
results[value] = 1;
}
}
var ret = [];
for(var word in results)
if(results[word]%2 !== 0)
rest.push(word);
return ret;
}
function even(list) {
var d = list.reduce(function(d, w) { d[w] = !d[w]; return d; }, {});
return Object.keys(d).filter(function(w) { return !d[w]; });
}
console.log(even(["hello", "hi", "hello", "elephant", "hi"]));
console.log(even(["hello", "yo", "yo", "hi", "hello", "yo", "elephant", "hi"]));
Explanation: Use the array .reduce() method to create an object (d) with a property for each word (w) with a boolean value indicating whether the word has an odd number of occurrences. Then .filter() the keys to get all the ones that are not odd.
If you previously sort the array you can filter it as required in just a code line like this :
var even = (str) => str.sort().filter((element, index, arr) => index+1 === arr.lastIndexOf(element));
console.log(even(["hello", "hello", "hi", "elephant", "hi", "hi"])); //[ 'hello', 'hi' ]
I'm trying to create a function that returns true if at least one of the elements of a string array is found within another string.
function findInString(str) {
var fruits = ["orange", "banana", "grape"];
for(var i = 0; i < fruits.length; i++) {
if (str.indexOf(fruits[i]) > -1) {
return true;
}
}
return false;
}
var a = findInString("I love orange juice."); //=> returns true
var b = findInString("I don't like peach."); //=> returns false
This function does the trick, but I'm sure there might some array or string method that does the same without having to loop through the array. Any ideas?
Thanks.
You could use some which comes very close to this. Here's how I'd write it:
function find (str, arr) {
return arr.some((s) => s.indexOf(str) > -1);
}
You could do this as well if you'd like but I don't feel good about it.
function find (str, arr) {
return arr.join(',').indexOf(str) > -1
}
You can use some function.
function findInString(str, arr) {
return arr.some(function(el) {
return str.indexOf(el) > -1;
});
}
var fruits = ["orange", "banana", "grape"];
var a = findInString("I love orange juice.", fruits); //=> returns true
var b = findInString("I don't like peach.", fruits); //=> returns false
I think you do have to process the array. I would make two changes.
First I would pass in the array as well as the string, making a generic function, then I would rework it so that once it finds one it quits doing that and exits the loop; similar concept as the return true but just a differing way to do it - my personal preference to only have one function exit.
function findInString(arr, str) {
var hasString = false;
for (var i = 0; i < fruits.length; i++) {
if (str.indexOf(fruits[i]) > -1) {
hasString = true;
break;
}
}
return hasString;
}
var fruits = ["orange", "banana", "grape"];
var a = findInString(fruits, "I love orange juice."); //=> returns true
var b = findInString(fruits, "I don't like peach."); //=> returns false
I like your way of doing it. I got a little into it, here are several ways you can think about doing this:
Some of these are really close, but that last period might require some string parsing to handle every case. Note the last one, since it uses RegExp, wont require doing anything to the string:
JsBin Example
function findInString(str) {
var fruits = ["orange", "banana", "grape"];
return str.split(' ').filter(function(el) {
return fruits.indexOf(el) > -1;
}).length > 0;
}
function finderWithReduce(str) {
var fruits = ["orange", "banana", "grape"];
var result = false;
str.split(' ').reduce(function(a, b) {
if (a.indexOf(b) > -1) {
result = true;
}
return a;
}, fruits);
return result;
}
function finderWithForEach(str){
var fruits = ["orange", "banana", "grape"];
var result = false;
fruits.forEach(function(fruit) {
if (str.indexOf(fruit) > -1) {
result = true;
}
});
return result;
}
function finderWithRegex(str) {
var fruits = ["orange", "banana", "grape"];
for (var i = 0; i < fruits.length; i++) {
var re = new RegExp(fruits[i], 'gi');
if (str.match(re) !== null) {
return true;
}
}
return false;
}
Here's a functional ES6 method. presentIn is a higher-order function that takes a string and returns a function that acts as the some callback.
const presentIn = (str) => (el) => str.includes(el);
fruits.some(presentIn('I love orange juice.')); // true
fruits.some(presentIn('I don\'t like peach.')); // false
I really like this approach because you're operating directly on the array elements, and if you name your function well it scans brilliantly: "Are some elements of the array present in the string".
DEMO
The slightly more verbose ES5 version for comparison:
function presentIn(str) {
return function (el) {
return str.indexOf(el) > -1;
}
}
Conceptually I can't think of a better (or even different) way of doing this. I don't know of a built in function which performs this task but even if there was one it's implementation would be this anyway.
This question already has answers here:
Simplest code for array intersection in javascript
(40 answers)
Closed 3 years ago.
I have two arrays, and I want to be able to compare the two and only return the values that match. For example both arrays have the value cat so that is what will be returned. I haven't found anything like this. What would be the best way to return similarities?
var array1 = ["cat", "sum","fun", "run"];
var array2 = ["bat", "cat","dog","sun", "hut", "gut"];
//if value in array1 is equal to value in array2 then return match: cat
You can use :
const intersection = array1.filter(element => array2.includes(element));
Naturally, my approach was to loop through the first array once and check the index of each value in the second array. If the index is > -1, then push it onto the returned array.
Array.prototype.diff = function(arr2) {
var ret = [];
for(var i in this) {
if(arr2.indexOf(this[i]) > -1){
ret.push(this[i]);
}
}
return ret;
};
My solution doesn't use two loops like others do so it may run a bit faster. If you want to avoid using for..in, you can sort both arrays first to reindex all their values:
Array.prototype.diff = function(arr2) {
var ret = [];
this.sort();
arr2.sort();
for(var i = 0; i < this.length; i += 1) {
if(arr2.indexOf(this[i]) > -1){
ret.push(this[i]);
}
}
return ret;
};
Usage would look like:
var array1 = ["cat", "sum","fun", "run", "hut"];
var array2 = ["bat", "cat","dog","sun", "hut", "gut"];
console.log(array1.diff(array2));
If you have an issue/problem with extending the Array prototype, you could easily change this to a function.
var diff = function(arr, arr2) {
And you'd change anywhere where the func originally said this to arr2.
I found a slight alteration on what #jota3 suggested worked perfectly for me.
var intersections = array1.filter(e => array2.indexOf(e) !== -1);
Hope this helps!
This function runs in O(n log(n) + m log(m)) compared to O(n*m) (as seen in the other solutions with loops/indexOf) which can be useful if you are dealing with lots of values.
However, because neither "a" > 1 nor "a" < 1, this only works for elements of the same type.
function intersect_arrays(a, b) {
var sorted_a = a.concat().sort();
var sorted_b = b.concat().sort();
var common = [];
var a_i = 0;
var b_i = 0;
while (a_i < a.length
&& b_i < b.length)
{
if (sorted_a[a_i] === sorted_b[b_i]) {
common.push(sorted_a[a_i]);
a_i++;
b_i++;
}
else if(sorted_a[a_i] < sorted_b[b_i]) {
a_i++;
}
else {
b_i++;
}
}
return common;
}
Example:
var array1 = ["cat", "sum", "fun", "hut"], //modified for additional match
array2 = ["bat", "cat", "dog", "sun", "hut", "gut"];
intersect_arrays(array1, array2);
>> ["cat", "hut"]
Loop through the second array each time you iterate over an element in the first array, then check for matches.
var array1 = ["cat", "sum", "fun", "run"],
array2 = ["bat", "cat", "dog", "sun", "hut", "gut"];
function getMatch(a, b) {
var matches = [];
for ( var i = 0; i < a.length; i++ ) {
for ( var e = 0; e < b.length; e++ ) {
if ( a[i] === b[e] ) matches.push( a[i] );
}
}
return matches;
}
getMatch(array1, array2); // ["cat"]
var array1 = [1, 2, 3, 4, 5, 6];
var array2 = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var array3 = array2.filter(function(obj) {
return array1.indexOf(obj) !== -1;
});
You can use javascript function .find()
As it says in MDN, it will return the first value that is true. If such an element is found, find immediately returns the value of that element. Otherwise, find returns undefined.
var array1 = ["cat", "sum", "fun", "run", "cat"];
var array2 = ["bat", "cat", "dog", "sun", "hut", "gut"];
found = array1.find((val, index) => {
console.log('index', index) // Stops at 0
return array2.includes(val)
})
console.log(found)
Or use .filter(), which loops through every elements first, then give back the result to you.
var array1 = ["cat", "sum", "fun", "run", "cat"];
var array2 = ["bat", "cat", "dog", "sun", "hut", "gut"];
found = array1.filter((val, index) => {
console.log('index', index) // Stops at array1.length - 1
return array2.includes(val)
})
console.log(found)
use lodash
GLOBAL.utils = require('lodash')
var arr1 = ['first' , 'second'];
var arr2 = ['second '];
var result = utils.difference(arr1 , arr2);
console.log ( "result :" + result );
Libraries like underscore and lodash have a utility method called intersection to find matches in arrays passed in. Take a look at: http://underscorejs.org/#intersection
Done as a answer so I can do formatting...
This is the the process you need to go through. Looping through an array for the specifics.
create an empty array
loop through array1, element by element. {
loop through array2, element by element {
if array1.element == array2.element {
add to your new array
}
}
}
If your values are non-null strings or numbers, you can use an object as a dictionary:
var map = {}, result = [], i;
for (i = 0; i < array1.length; ++i) {
map[array1[i]] = 1;
}
for (i = 0; i < array2.length; ++i) {
if (map[array2[i]] === 1) {
result.push(array2[i]);
// avoid returning a value twice if it appears twice in array 2
map[array2[i]] = 0;
}
}
return result;
With some ES6:
let sortedArray = [];
firstArr.map((first) => {
sortedArray[defaultArray.findIndex(def => def === first)] = first;
});
sortedArray = sortedArray.filter(v => v);
This snippet also sorts the firstArr based on the order of the defaultArray
like:
let firstArr = ['apple', 'kiwi', 'banana'];
let defaultArray = ['kiwi', 'apple', 'pear'];
...
console.log(sortedArray);
// ['kiwi', 'apple'];
Iterate on array1 and find the indexof element present in array2.
var array1 = ["cat", "sum","fun", "run"];
var array2 = ["bat", "cat","sun", "hut", "gut"];
var str='';
for(var i=0;i<array1.length;i++){
if(array2.indexOf(array1[i]) != -1){
str+=array1[i]+' ';
};
}
console.log(str)
I have a target array ["apple","banana","orange"], and I want to check if other arrays contain any one of the target array elements.
For example:
["apple","grape"] //returns true;
["apple","banana","pineapple"] //returns true;
["grape", "pineapple"] //returns false;
How can I do it in JavaScript?
Vanilla JS
ES2016:
const found = arr1.some(r=> arr2.includes(r))
ES6:
const found = arr1.some(r=> arr2.indexOf(r) >= 0)
How it works
some(..) checks each element of the array against a test function and returns true if any element of the array passes the test function, otherwise, it returns false. indexOf(..) >= 0 and includes(..) both return true if the given argument is present in the array.
vanilla js
/**
* #description determine if an array contains one or more items from another array.
* #param {array} haystack the array to search.
* #param {array} arr the array providing items to check for in the haystack.
* #return {boolean} true|false if haystack contains at least one item from arr.
*/
var findOne = function (haystack, arr) {
return arr.some(function (v) {
return haystack.indexOf(v) >= 0;
});
};
As noted by #loganfsmyth you can shorten it in ES2016 to
/**
* #description determine if an array contains one or more items from another array.
* #param {array} haystack the array to search.
* #param {array} arr the array providing items to check for in the haystack.
* #return {boolean} true|false if haystack contains at least one item from arr.
*/
const findOne = (haystack, arr) => {
return arr.some(v => haystack.includes(v));
};
or simply as arr.some(v => haystack.includes(v));
If you want to determine if the array has all the items from the other array, replace some() to every()
or as arr.every(v => haystack.includes(v));
ES6 solution:
let arr1 = [1, 2, 3];
let arr2 = [2, 3];
let isFounded = arr1.some( ai => arr2.includes(ai) );
Unlike of it: Must contains all values.
let allFounded = arr2.every( ai => arr1.includes(ai) );
Hope, will be helpful.
If you're not opposed to using a libray, http://underscorejs.org/ has an intersection method, which can simplify this:
var _ = require('underscore');
var target = [ 'apple', 'orange', 'banana'];
var fruit2 = [ 'apple', 'orange', 'mango'];
var fruit3 = [ 'mango', 'lemon', 'pineapple'];
var fruit4 = [ 'orange', 'lemon', 'grapes'];
console.log(_.intersection(target, fruit2)); //returns [apple, orange]
console.log(_.intersection(target, fruit3)); //returns []
console.log(_.intersection(target, fruit4)); //returns [orange]
The intersection function will return a new array with the items that it matched and if not matches it returns empty array.
ES6 (fastest)
const a = ['a', 'b', 'c'];
const b = ['c', 'a', 'd'];
a.some(v=> b.indexOf(v) !== -1)
ES2016
const a = ['a', 'b', 'c'];
const b = ['c', 'a', 'd'];
a.some(v => b.includes(v));
Underscore
const a = ['a', 'b', 'c'];
const b = ['c', 'a', 'd'];
_.intersection(a, b)
DEMO: https://jsfiddle.net/r257wuv5/
jsPerf: https://jsperf.com/array-contains-any-element-of-another-array
If you don't need type coercion (because of the use of indexOf), you could try something like the following:
var arr = [1, 2, 3];
var check = [3, 4];
var found = false;
for (var i = 0; i < check.length; i++) {
if (arr.indexOf(check[i]) > -1) {
found = true;
break;
}
}
console.log(found);
Where arr contains the target items. At the end, found will show if the second array had at least one match against the target.
Of course, you can swap out numbers for anything you want to use - strings are fine, like your example.
And in my specific example, the result should be true because the second array's 3 exists in the target.
UPDATE:
Here's how I'd organize it into a function (with some minor changes from before):
var anyMatchInArray = (function () {
"use strict";
var targetArray, func;
targetArray = ["apple", "banana", "orange"];
func = function (checkerArray) {
var found = false;
for (var i = 0, j = checkerArray.length; !found && i < j; i++) {
if (targetArray.indexOf(checkerArray[i]) > -1) {
found = true;
}
}
return found;
};
return func;
}());
DEMO: http://jsfiddle.net/u8Bzt/
In this case, the function could be modified to have targetArray be passed in as an argument instead of hardcoded in the closure.
UPDATE2:
While my solution above may work and be (hopefully more) readable, I believe the "better" way to handle the concept I described is to do something a little differently. The "problem" with the above solution is that the indexOf inside the loop causes the target array to be looped over completely for every item in the other array. This can easily be "fixed" by using a "lookup" (a map...a JavaScript object literal). This allows two simple loops, over each array. Here's an example:
var anyMatchInArray = function (target, toMatch) {
"use strict";
var found, targetMap, i, j, cur;
found = false;
targetMap = {};
// Put all values in the `target` array into a map, where
// the keys are the values from the array
for (i = 0, j = target.length; i < j; i++) {
cur = target[i];
targetMap[cur] = true;
}
// Loop over all items in the `toMatch` array and see if any of
// their values are in the map from before
for (i = 0, j = toMatch.length; !found && (i < j); i++) {
cur = toMatch[i];
found = !!targetMap[cur];
// If found, `targetMap[cur]` will return true, otherwise it
// will return `undefined`...that's what the `!!` is for
}
return found;
};
DEMO: http://jsfiddle.net/5Lv9v/
The downside to this solution is that only numbers and strings (and booleans) can be used (correctly), because the values are (implicitly) converted to strings and set as the keys to the lookup map. This isn't exactly good/possible/easily done for non-literal values.
Using filter/indexOf:
function containsAny(source,target)
{
var result = source.filter(function(item){ return target.indexOf(item) > -1});
return (result.length > 0);
}
//results
var fruits = ["apple","banana","orange"];
console.log(containsAny(fruits,["apple","grape"]));
console.log(containsAny(fruits,["apple","banana","pineapple"]));
console.log(containsAny(fruits,["grape", "pineapple"]));
You could use lodash and do:
_.intersection(originalTarget, arrayToCheck).length > 0
Set intersection is done on both collections producing an array of identical elements.
const areCommonElements = (arr1, arr2) => {
const arr2Set = new Set(arr2);
return arr1.some(el => arr2Set.has(el));
};
Or you can even have a better performance if you first find out which of these two arrays is longer and making Set out for the longest array, while applying some method on the shortest one:
const areCommonElements = (arr1, arr2) => {
const [shortArr, longArr] = (arr1.length < arr2.length) ? [arr1, arr2] : [arr2, arr1];
const longArrSet = new Set(longArr);
return shortArr.some(el => longArrSet.has(el));
};
I wrote 3 solutions. Essentially they do the same. They return true as soon as they get true. I wrote the 3 solutions just for showing 3 different way to do things. Now, it depends what you like more. You can use performance.now() to check the performance of one solution or the other. In my solutions I'm also checking which array is the biggest and which one is the smallest to make the operations more efficient.
The 3rd solution may not be the cutest but is efficient. I decided to add it because in some coding interviews you are not allowed to use built-in methods.
Lastly, sure...we can come up with a solution with 2 NESTED for loops (the brute force way) but you want to avoid that because the time complexity is bad O(n^2).
Note:
instead of using .includes() like some other people did, you can use
.indexOf(). if you do just check if the value is bigger than 0. If
the value doesn't exist will give you -1. if it does exist, it will give you
greater than 0.
indexOf() vs includes()
Which one has better performance? indexOf() for a little bit, but includes is more readable in my opinion.
If I'm not mistaken .includes() and indexOf() use loops behind the scene, so you will be at O(n^2) when using them with .some().
USING loop
const compareArraysWithIncludes = (arr1, arr2) => {
const [smallArray, bigArray] =
arr1.length < arr2.length ? [arr1, arr2] : [arr2, arr1];
for (let i = 0; i < smallArray.length; i++) {
return bigArray.includes(smallArray[i]);
}
return false;
};
USING .some()
const compareArraysWithSome = (arr1, arr2) => {
const [smallArray, bigArray] =
arr1.length < arr2.length ? [arr1, arr2] : [arr2, arr1];
return smallArray.some(c => bigArray.includes(c));
};
USING MAPS Time complexity O(2n)=>O(n)
const compararArraysUsingObjs = (arr1, arr2) => {
const map = {};
const [smallArray, bigArray] =
arr1.length < arr2.length ? [arr1, arr2] : [arr2, arr1];
for (let i = 0; i < smallArray.length; i++) {
if (!map[smallArray[i]]) {
map[smallArray[i]] = true;
}
}
for (let i = 0; i < bigArray.length; i++) {
if (map[bigArray[i]]) {
return true;
}
}
return false;
};
Code in my:
stackblitz
I'm not an expert in performance nor BigO so if something that I said is wrong let me know.
You can use a nested Array.prototype.some call. This has the benefit that it will bail at the first match instead of other solutions that will run through the full nested loop.
eg.
var arr = [1, 2, 3];
var match = [2, 4];
var hasMatch = arr.some(a => match.some(m => a === m));
I found this short and sweet syntax to match all or some elements between two arrays. For example
// OR operation. find if any of array2 elements exists in array1. This will return as soon as there is a first match as some method breaks when function returns TRUE
let array1 = ['a', 'b', 'c', 'd', 'e'], array2 = ['a', 'b'];
console.log(array2.some(ele => array1.includes(ele)));
// prints TRUE
// AND operation. find if all of array2 elements exists in array1. This will return as soon as there is a no first match as some method breaks when function returns TRUE
let array1 = ['a', 'b', 'c', 'd', 'e'], array2 = ['a', 'x'];
console.log(!array2.some(ele => !array1.includes(ele)));
// prints FALSE
Hope that helps someone in future!
Just one more solution
var a1 = [1, 2, 3, 4, 5]
var a2 = [2, 4]
Check if a1 contain all element of a2
var result = a1.filter(e => a2.indexOf(e) !== -1).length === a2.length
console.log(result)
What about using a combination of some/findIndex and indexOf?
So something like this:
var array1 = ["apple","banana","orange"];
var array2 = ["grape", "pineapple"];
var found = array1.some(function(v) { return array2.indexOf(v) != -1; });
To make it more readable you could add this functionality to the Array object itself.
Array.prototype.indexOfAny = function (array) {
return this.findIndex(function(v) { return array.indexOf(v) != -1; });
}
Array.prototype.containsAny = function (array) {
return this.indexOfAny(array) != -1;
}
Note: If you'd want to do something with a predicate you could replace the inner indexOf with another findIndex and a predicate
Here is an interesting case I thought I should share.
Let's say that you have an array of objects and an array of selected filters.
let arr = [
{ id: 'x', tags: ['foo'] },
{ id: 'y', tags: ['foo', 'bar'] },
{ id: 'z', tags: ['baz'] }
];
const filters = ['foo'];
To apply the selected filters to this structure we can
if (filters.length > 0)
arr = arr.filter(obj =>
obj.tags.some(tag => filters.includes(tag))
);
// [
// { id: 'x', tags: ['foo'] },
// { id: 'y', tags: ['foo', 'bar'] }
// ]
Good perfomance solution:
We should transform one of arrays to object.
const contains = (arr1, mainObj) => arr1.some(el => el in mainObj);
const includes = (arr1, mainObj) => arr1.every(el => el in mainObj);
Usage:
const mainList = ["apple", "banana", "orange"];
// We make object from array, you can use your solution to make it
const main = Object.fromEntries(mainList.map(key => [key, true]));
contains(["apple","grape"], main) // => true
contains(["apple","banana","pineapple"], main) // => true
contains(["grape", "pineapple"], main) // => false
includes(["apple", "grape"], main) // => false
includes(["banana", "apple"], main) // => true
you can face with some disadvantage of checking by in operator (eg 'toString' in {} // => true), so you can change solution to obj[key] checker
Adding to Array Prototype
Disclaimer: Many would strongly advise against this. The only time it'd really be a problem was if a library added a prototype function with the same name (that behaved differently) or something like that.
Code:
Array.prototype.containsAny = function(arr) {
return this.some(
(v) => (arr.indexOf(v) >= 0)
)
}
Without using big arrow functions:
Array.prototype.containsAny = function(arr) {
return this.some(function (v) {
return arr.indexOf(v) >= 0
})
}
Usage
var a = ["a","b"]
console.log(a.containsAny(["b","z"])) // Outputs true
console.log(a.containsAny(["z"])) // Outputs false
My solution applies Array.prototype.some() and Array.prototype.includes() array helpers which do their job pretty efficient as well
ES6
const originalFruits = ["apple","banana","orange"];
const fruits1 = ["apple","banana","pineapple"];
const fruits2 = ["grape", "pineapple"];
const commonFruits = (myFruitsArr, otherFruitsArr) => {
return myFruitsArr.some(fruit => otherFruitsArr.includes(fruit))
}
console.log(commonFruits(originalFruits, fruits1)) //returns true;
console.log(commonFruits(originalFruits, fruits2)) //returns false;
When I looked at your answers, I could not find the answer I wanted.
I did something myself and I want to share this with you.
It will be true only if the words entered (array) are correct.
function contains(a,b) {
let counter = 0;
for(var i = 0; i < b.length; i++) {;
if(a.includes(b[i])) counter++;
}
if(counter === b.length) return true;
return false;
}
let main_array = ['foo','bar','baz'];
let sub_array_a = ['foo','foobar'];
let sub_array_b = ['foo','bar'];
console.log(contains(main_array, sub_array_a)); // returns false
console.log(contains(main_array,sub_array_b )); // returns true
Array .filter() with a nested call to .find() will return all elements in the first array that are members of the second array. Check the length of the returned array to determine if any of the second array were in the first array.
getCommonItems(firstArray, secondArray) {
return firstArray.filter((firstArrayItem) => {
return secondArray.find((secondArrayItem) => {
return firstArrayItem === secondArrayItem;
});
});
}
It can be done by simply iterating across the main array and check whether other array contains any of the target element or not.
Try this:
function Check(A) {
var myarr = ["apple", "banana", "orange"];
var i, j;
var totalmatches = 0;
for (i = 0; i < myarr.length; i++) {
for (j = 0; j < A.length; ++j) {
if (myarr[i] == A[j]) {
totalmatches++;
}
}
}
if (totalmatches > 0) {
return true;
} else {
return false;
}
}
var fruits1 = new Array("apple", "grape");
alert(Check(fruits1));
var fruits2 = new Array("apple", "banana", "pineapple");
alert(Check(fruits2));
var fruits3 = new Array("grape", "pineapple");
alert(Check(fruits3));
DEMO at JSFIDDLE
Not sure how efficient this might be in terms of performance, but this is what I use using array destructuring to keep everything nice and short:
const shareElements = (arr1, arr2) => {
const typeArr = [...arr1, ...arr2]
const typeSet = new Set(typeArr)
return typeArr.length > typeSet.size
}
Since sets cannot have duplicate elements while arrays can, combining both input arrays, converting it to a set, and comparing the set size and array length would tell you if they share any elements.
A short way of writing this:
const found = arr1.some(arr2.includes)
With underscorejs
var a1 = [1,2,3];
var a2 = [1,2];
_.every(a1, function(e){ return _.include(a2, e); } ); //=> false
_.every(a2, function(e){ return _.include(a1, e); } ); //=> true
Vanilla JS with partial matching & case insensitive
The problem with some previous approaches is that they require an exact match of every word. But, What if you want to provide results for partial matches?
function search(arrayToSearch, wordsToSearch) {
arrayToSearch.filter(v =>
wordsToSearch.every(w =>
v.toLowerCase().split(" ").
reduce((isIn, h) => isIn || String(h).indexOf(w) >= 0, false)
)
)
}
//Usage
var myArray = ["Attach tag", "Attaching tags", "Blah blah blah"];
var searchText = "Tag attach";
var searchArr = searchText.toLowerCase().split(" "); //["tag", "attach"]
var matches = search(myArray, searchArr);
//Will return
//["Attach tag", "Attaching tags"]
This is useful when you want to provide a search box where users type words and the results can have those words in any order, position and case.
Update #Paul Grimshaw answer, use includes insteed of indexOf for more readable
let found = arr1.some(r=> arr2.indexOf(r) >= 0)
let found = arr1.some(r=> arr2.includes(r))
I came up with a solution in node using underscore js like this:
var checkRole = _.intersection(['A','B'], ['A','B','C']);
if(!_.isEmpty(checkRole)) {
next();
}
You are looking for intersection between the two arrays. And you have two major intersection types: 'every' and 'some'. Let me give you good examples:
EVERY
let brands1 = ['Ford', 'Kia', 'VW', 'Audi'];
let brands2 = ['Audi', 'Kia'];
// Find 'every' brand intersection.
// Meaning all elements inside 'brands2' must be present in 'brands1':
let intersectionEvery = brands2.every( brand => brands1.includes(brand) );
if (intersectionEvery) {
const differenceList = brands1.filter(brand => !brands2.includes(brand));
console.log('difference list:', differenceList);
const commonList = brands1.filter(brand => brands2.includes(brand));
console.log('common list:', commonList);
}
If condition is not met (like if you put 'Mercedes' in brands2) then 'intersectionEvery' won't be satisfied - will be bool false.
If condition is met it will log ["Ford", "VW"] as difference and ["Kia", "Audi"] as common list.
Sandbox: https://jsfiddle.net/bqmg14t6/
SOME
let brands1 = ['Ford', 'Kia', 'VW', 'Audi'];
let brands2 = ['Audi', 'Kia', 'Mercedes', 'Land Rover'];
// Find 'some' brand intersection.
// Meaning some elements inside 'brands2' must be also present in 'brands1':
let intersectionSome = brands2.some( brand => brands1.includes(brand) );
if (intersectionSome) {
const differenceList = brands1.filter(brand => !brands2.includes(brand));
console.log('difference list:', differenceList);
const commonList = brands1.filter(brand => brands2.includes(brand));
console.log('common list:', commonList);
}
Here we are looking for some common brands, not necessarily all.
It will log ["Ford", "VW"] as difference and ["Kia", "Audi"] as common brands.
Sandbox: https://jsfiddle.net/zkq9j3Lh/
Personally, I would use the following function:
var arrayContains = function(array, toMatch) {
var arrayAsString = array.toString();
return (arrayAsString.indexOf(','+toMatch+',') >-1);
}
The "toString()" method will always use commas to separate the values. Will only really work with primitive types.
console.log("searching Array: "+finding_array);
console.log("searching in:"+reference_array);
var check_match_counter = 0;
for (var j = finding_array.length - 1; j >= 0; j--)
{
if(reference_array.indexOf(finding_array[j]) > 0)
{
check_match_counter = check_match_counter + 1;
}
}
var match = (check_match_counter > 0) ? true : false;
console.log("Final result:"+match);