检查一个数组是否包含JavaScript中另一个数组的任何元素

我有一个目标数组["apple","banana","orange"],我想检查其他数组是否包含任何一个目标数组元素。

例如:

["apple","grape"] //returns true;
["apple","banana","pineapple"] //returns true;
["grape", "pineapple"] //returns false;

我如何在JavaScript中做到这一点?

932646 次浏览

如果您不需要类型强制(因为使用了indexOf),您可以尝试以下操作:

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);

其中arr包含目标项。最后,found将显示第二个数组是否与目标至少一个匹配。

当然,你可以用数字交换任何你想使用的东西——字符串很好,就像你的例子一样。

在我的具体示例中,结果应该是true,因为第二个数组的3存在于目标中。


更新:

这是我如何将它组织成一个函数(与之前相比有一些小的变化):

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;}());

演示:http://jsfiddle.net/u8Bzt/

在这种情况下,可以修改函数以使targetArray作为参数传入,而不是在闭包中硬编码。


更新2:

虽然我上面的解决方案可能有效并且(希望更)可读,但我相信处理我描述的概念的“更好”方法是做一些不同的事情。上述解决方案的“问题”是循环中的indexOf导致目标数组对另一个数组中的每个项目都完全循环。这可以通过使用“查找”(映射… JavaScript对象文字)轻松“修复”。这允许在每个数组上进行两个简单的循环。这是一个例子:

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 arrayfor (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 beforefor (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;};

演示:http://jsfiddle.net/5Lv9v/

这种解决方案的缺点是只能(正确地)使用数字和字符串(以及布尔值),因为这些值被(隐式地)转换为字符串并设置为查找映射的键。对于非文字值来说,这并不好/可能/容易做到。

如果你不反对使用库,http://underscorejs.org/有一个交集方法,它可以简化这一点:

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]

交集函数将返回一个包含它匹配的项目的新数组,如果不匹配,则返回空数组。

它可以通过简单地遍历主数组并检查其他数组是否包含任何目标元素来完成。

试试这个:

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));

JSFIDDLE演示

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

/*** @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;});};

正如@loganfsmyth所指出的,您可以在ES2016中将其缩短为

/*** @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));};

或者只是arr.some(v => haystack.includes(v));

如果要确定数组是否包含另一个数组中的所有项,请将some()替换为every()arr.every(v => haystack.includes(v));

如何使用一些/findIndex和indexOf的组合?

所以像这样:

var array1 = ["apple","banana","orange"];var array2 = ["grape", "pineapple"];
var found = array1.some(function(v) { return array2.indexOf(v) != -1; });

为了使其更具可读性,您可以将此功能添加到Array对象本身。

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;}

注意:如果你想用谓词做某事,你可以用另一个findIndex和谓词替换内部indexOf

使用过滤器/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"]));

就个人而言,我将使用以下功能:

var arrayContains = function(array, toMatch) {var arrayAsString = array.toString();return (arrayAsString.indexOf(','+toMatch+',') >-1);}

toString()方法将始终使用逗号分隔值。仅适用于原始类型。

添加到数组原型

免责声明:许多人强烈反对这样做。唯一真正有问题的是,如果库添加了同名(行为不同)的原型函数或类似的东西。

代码:

Array.prototype.containsAny = function(arr) {return this.some((v) => (arr.indexOf(v) >= 0))}

不使用大箭头函数:

Array.prototype.containsAny = function(arr) {return this.some(function (v) {return arr.indexOf(v) >= 0})}

用法

var a = ["a","b"]
console.log(a.containsAny(["b","z"]))    // Outputs true
console.log(a.containsAny(["z"]))    // Outputs false

您可以使用豆沙并执行:

_.intersection(originalTarget, arrayToCheck).length > 0

集合交集在两个集合上完成,产生相同元素的数组。

我想出了一个使用下划线js的节点解决方案,如下所示:

var checkRole = _.intersection(['A','B'], ['A','B','C']);if(!_.isEmpty(checkRole)) {next();}

香草JS

ES2016:

const found = arr1.some(r=> arr2.includes(r))

ES6:

const found = arr1.some(r=> arr2.indexOf(r) >= 0)

它是如何运作的

some(..)根据测试函数检查数组的每个元素,如果数组中的任何元素通过测试函数,则返回true,否则返回false。如果数组中存在给定参数,则indexOf(..) >= 0includes(..)都返回true。

.find()进行嵌套调用的数组.filter()将返回第一个数组中属于第二个数组成员的所有元素。检查返回数组的长度以确定是否有第二个数组在第一个数组中。

getCommonItems(firstArray, secondArray) {return firstArray.filter((firstArrayItem) => {return secondArray.find((secondArrayItem) => {return firstArrayItem === secondArrayItem;});});}

ES6(最快)

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));

下划线

const a = ['a', 'b', 'c'];const b = ['c', 'a', 'd'];_.intersection(a, b)

演示:https://jsfiddle.net/r257wuv5/

jsPerf:https://jsperf.com/array-contains-any-element-of-another-array相关文档

部分匹配和不区分大小写的Vanilla JS

以前的一些方法的问题是它们需要每个单词的精确匹配。但是,如果您想提供部分匹配的结果怎么办?

function search(arrayToSearch, wordsToSearch) {arrayToSearch.filter(v =>wordsToSearch.every(w =>v.toLowerCase().split(" ").reduce((isIn, h) => isIn || String(h).indexOf(w) >= 0, false)))}//Usagevar 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"]

当您想提供一个用户键入单词的搜索框并且结果可以以任何顺序、位置和大小写包含这些单词时,这很有用。

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);

更新@Paul Grimshaw答案,使用includes代替indexOf更具可读性

让发现=arr1.some(r=>arr2.indexOf(r)>=0)
arr1.some(r=>arr2.includes(r))

您可以使用嵌套Array.prototype.some调用。这样做的好处是它将在第一次匹配时退出,而不是其他将贯穿整个嵌套循环的解决方案。

eg.

var arr = [1, 2, 3];var match = [2, 4];
var hasMatch = arr.some(a => match.some(m => a === m));

这是一个有趣的案例,我想我应该分享。

假设您有一个对象数组和一个选定过滤器数组。

let arr = [{ id: 'x', tags: ['foo'] },{ id: 'y', tags: ['foo', 'bar'] },{ id: 'z', tags: ['baz'] }];
const filters = ['foo'];

要将所选过滤器应用于此结构,我们可以

if (filters.length > 0)arr = arr.filter(obj =>obj.tags.some(tag => filters.includes(tag)));
// [//   { id: 'x', tags: ['foo'] },//   { id: 'y', tags: ['foo', 'bar'] }// ]

我发现这个简短而甜蜜的语法可以匹配两个数组之间的所有或某些元素。例如

//OR操作。查找array1中是否存在array2元素。一旦有第一个匹配,这将返回,因为当函数返回TRUE时某些方法中断

let array1 = ['a', 'b', 'c', 'd', 'e'], array2 = ['a', 'b'];
console.log(array2.some(ele => array1.includes(ele)));

//输出结果为真

//与操作。查找array1中是否存在所有array2元素。一旦没有第一个匹配,这将返回,因为当函数返回TRUE时某些方法中断

let array1 = ['a', 'b', 'c', 'd', 'e'], array2 = ['a', 'x'];
console.log(!array2.some(ele => !array1.includes(ele)));

//输出错误信息

希望将来能帮助到别人!

var target = ["apple","banana","orange"];var checkArray = ["apple","banana","pineapple"];
var containsOneCommonItem = target.some(x => checkArray.some(y => y === x));`
["apple","grape"] //returns true;
["apple","banana","pineapple"] //returns true;
["grape", "pineapple"] //returns false;

我的解决方案适用于Array.prototype.some()Array.prototype.includes()数组助手,它们的工作也非常高效

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;

ES6解决方案:

let arr1 = [1, 2, 3];let arr2 = [2, 3];
let isFounded = arr1.some( ai => arr2.includes(ai) );

与之不同的是:必须包含所有值。

let allFounded = arr2.every( ai => arr1.includes(ai) );

希望,会有所帮助。

还有一个解决方案

var a1 = [1, 2, 3, 4, 5]var a2 = [2, 4]

检查a1是否包含a2的所有元素

var result = a1.filter(e => a2.indexOf(e) !== -1).length === a2.lengthconsole.log(result)
const areCommonElements = (arr1, arr2) => {const arr2Set = new Set(arr2);return arr1.some(el => arr2Set.has(el));};

或者,如果您首先找出这两个数组中的哪个更长,并将Set作为最长的数组,同时在最短的数组上应用some方法,您甚至可以获得更好的性能:

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));};

我写了3个解决方案。本质上它们做的是一样的。它们在得到true后立即返回true。我写这3个解决方案只是为了展示3种不同的做事方式。现在,这取决于你更喜欢什么。你可以使用performance.now()来检查一个解决方案或另一个解决方案的性能。在我的解决方案中,我还检查哪个数组最大,哪个数组最小,以提高操作效率。

第三种解决方案可能不是最可爱的,但很有效。我决定添加它,因为在一些编码面试中,您不允许使用内置方法。

最后,当然……我们可以想出一个带有2个嵌套循环的解决方案(蛮力方式),但你想避免这种情况,因为时间复杂度不好O(n^2)

备注:

而不是像其他人那样使用.includes(),您可以使用.indexOf()。如果您检查值是否大于0。如果值不存在会给你-1。如果它确实存在,它会给你大于0.

indexOf()vs包括()

哪一个有更好的性能indexOf()有点,但在我看来,包含更具可读性。

如果我没有弄错.includes()indexOf()在场景后面使用循环,所以你将在.some()使用它们时处于O(n^2)

使用循环

 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;};

使用一些()

const compareArraysWithSome = (arr1, arr2) => {const [smallArray, bigArray] =arr1.length < arr2.length ? [arr1, arr2] : [arr2, arr1];return smallArray.some(c => bigArray.includes(c));};

使用地图时间复杂度 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;};

我的代码:stackblitz

我不是性能方面的专家,也不是BigO,所以如果我说的是错误的,请告诉我。

不确定这在性能方面有多高效,但这就是我使用数组解构来保持一切美好和简短的原因:

const shareElements = (arr1, arr2) => {const typeArr = [...arr1, ...arr2]const typeSet = new Set(typeArr)return typeArr.length > typeSet.size}

由于集合不能具有重复的元素,而数组可以,因此组合两个输入数组,将其转换为集合,并比较集合大小和数组长度将告诉您它们是否共享任何元素。

当我看到你的答案时,我找不到我想要的答案。我自己做了一件事,我想和你分享。

仅当输入的单词(数组)正确时才为真。

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 falseconsole.log(contains(main_array,sub_array_b )); // returns true

你可以做这样的事

let filteredArray = array.filter((elm) => {for (let i=0; i<anotherAray.length; i++) {return elm.includes(anotherArray[i])}})

良好的性能解决方案:

我们应该将数组之一转换为对象。

const contains = (arr1, mainObj) => arr1.some(el => el in mainObj);const includes = (arr1, mainObj) => arr1.every(el => el in mainObj);

用法:

const mainList = ["apple", "banana", "orange"];// We make object from array, you can use your solution to make itconst main = Object.fromEntries(mainList.map(key => [key, true]));
contains(["apple","grape"], main) // => truecontains(["apple","banana","pineapple"], main) // =>  truecontains(["grape", "pineapple"], main) // =>  false
includes(["apple", "grape"], main) // => falseincludes(["banana", "apple"], main) // =>  true

您可能会面临在操作员检查的一些缺点(例如 {} // =>; true中的'toString'),因此您可以将解决方案更改为obj[key]检查器

您正在寻找两个数组之间的交集。并且您有两种主要的交集类型:“每个”和“一些”。让我给你举个好例子:

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);}

如果条件不满足(比如如果你把“梅赛德斯”放在品牌2中),那么“intersectionAll”将不会被满足-将是bool false。

如果条件满足,它将记录[“福特”,“大众”]作为差异和[“起亚”,“奥迪”]作为共同列表。

沙盒:https://jsfiddle.net/bqmg14t6/

一些

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);}

这里我们要找的是一些常见的品牌,不一定都是。

它将记录[“福特”,“大众”]作为差异,[“起亚”,“奥迪”]作为常见品牌。

沙盒:https://jsfiddle.net/zkq9j3Lh/

一个简短的写法:const found = arr1.some(arr2.includes)