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


406

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

例如:

["apple","grape"] //returns true;

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

["grape", "pineapple"] //returns false;

如何在JavaScript中完成?


3
使用for循环并遍历目标数组。如果每个元素都包含在当前数组中(使用current.indexOf(elem) !== -1),则它们都在其中。)
Blender

21
@Alex选择一个答案花花公子,不加选择地保留答案是不礼貌的,尤其是拥有这么多好的答案时。如果我是你,我会选择下划线/破折号。
里昂·加班

1
@LeonGaban我不同意。我不会为了执行此操作而导入库。
devpato

2
@devpato是的,我改变了主意,ES6解决方案是我的最爱
Leon Gaban

怎么样arr1.some(el1 => arr2.includes(el1)); ?
Walaszka

Answers:


551

香草JS

ES2016:

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

ES6:

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

怎么运行的

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


48
这段代码需要解释-这可能
有用

6
Array.prototype.some()根据测试函数检查数组的每个元素,并返回true数组的任何元素是否通过测试函数。否则,返回false
Hendeca

2
这应该是正确的答案!伟大的人使用ES6
Nacho

1
是否期望我的结果[false, false, false]不是空数组[]
蝙蝠侠

@蝙蝠侠:结果是对还是错,但您可以改用
skyisred

230

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

10
不错的解决方案! some()是拉德。匹配后立即退出。
averydev '16

6
事件整理如下:arr.some(v=> haystack.indexOf(v) >= 0)
Paul Grimshaw

85
在ES2016中也可用arr.some(v => haystack.includes(v))
loganfsmyth '16

5
在一排arr1.some(v => arr2.indexOf(v) >= 0)
webjay

1
现在,它可能是最好避免使用includes,因为显然它不支持IE:stackoverflow.com/questions/36574351/...
Shafique先生贾马尔

72

如果您不反对使用libray,则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]

相交函数将返回一个具有匹配项的新数组,如果不匹配,则返回空数组。


3
我已经使用了几次,但是请注意,问题是关于检查另一个数组中是否存在任何元素,而不是生成整个交集。就性能而言,如果数组很大,则存在巨大差异,因为在第一种情况下,一旦找到匹配项,您就可以纾困。
JHH

1
lodash比香草Javascript更具可读性,应始终使用Ramda之类的库代替香草imho。更适合所有开发者...
Leon Gaban

52

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


1
这是最简单和声明性的解决方案
strider

我知道我真的来晚了,但是要检查控制台是否JSFiddle添加了JQuery Edge并打开Firebug Lite
Rojo

JSperf链接断开
DarckBlezzer

时间和空间复杂度是否有差异?关于复杂性的最佳解决方案是什么?
nacho

41

如果您不需要类型强制(由于使用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作为参数传递,而不是在闭包中进行硬编码。


UPDATE2:

尽管我上面的解决方案可能会起作用,并且(希望是)可读性更高,但我认为处理我描述的概念的“更好”的方法是做一些不同的事情。上述解决方案的“问题”是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 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;
};

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

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


2
优秀的例子,第二个例子简直太棒了。
Sorin Haidau 2014年

为什么在可以使用一些或findIndex的同时使用for循环?
是我...亚历克斯(Alex)2014年

1
“ some”极大地简化了代码。同样,anyMatchInArray([1,2,3,“ cats”,“ 4”],[“ 1”,4])为true。最后,如果您有大量查找并缓存了targetMap,这可能会更有效。即使这样,也可能会提高性能。例如,我猜想“找到= toMatch [i]!==未定义”会更有效,在某些情况下会更好(这样您就不会评估“”或0到false)
csga5000

“否则它将返回undefined……这就是要做什么!!”-这是错误的。它将返回的布尔反对!
AlienWebguy

41

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

希望会有所帮助。


有什么方法可以从array1获取arra2值的索引吗?
安齐尔·卡恩,

1
在这种情况下,我们可以使用“过滤器”代替“一些”。然后它将返回一个数组,而不是布尔值,您可以从那里轻松访问值。
tanvir993

29

您可以使用lodash并执行以下操作:

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

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


就性能而言,它不是最佳的,因为对于此问题,找到第一个匹配项就足够了,而intersection即使找到第一个匹配项也将继续比较以便找到所有匹配项。就像filter在需要时使用find
亚历山大·

29

使用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"]));


与库函数(如_.intersection)存在相同的问题,即使找到匹配项,它也会继续寻找匹配项。显然,对于小型阵列而言,这并不重要。
JHH

12
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
虽然不断有人用筑巢发布解决方案indexOfincludes,你是第一个与更高效的基于集合的解决方案来回答,使用本机Set,它引入的EcmaScript后4年。+1
童车

9

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

//或运算。查找array1中是否存在任何array2元素。一旦有第一个匹配项,函数将返回TRUE时,该方法将中断,这将立即返回

let array1 = ['a', 'b', 'c', 'd', 'e'], array2 = ['a', 'b'];

console.log(array2.some(ele => array1.includes(ele)));

//打印TRUE

// AND运算。查找array1中是否存在所有array2元素。如果没有第一个匹配项,它将返回,因为当函数返回TRUE时某些方法中断

let array1 = ['a', 'b', 'c', 'd', 'e'], array2 = ['a', 'x'];

console.log(!array2.some(ele => !array1.includes(ele)));

//打印FALSE

希望以后能对某人有所帮助!


我真的很喜欢问题的第二部分,使其适用于ES5,它的工作方式如下:!array2.some(function(ele){return array1.indexOf(ele)=== -1});
Friesgaard

6

您可以使用嵌套的Array.prototype.some调用。这样的好处是它将在第一次比赛时保释,而不是在整个嵌套循环中运行的其他解决方案。

例如。

var arr = [1, 2, 3];
var match = [2, 4];

var hasMatch = arr.some(a => match.some(m => a === m));

4

我想分享一个有趣的案例。

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

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'] }
// ]

4

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

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

最后,确定...我们可以提出一个带有2个NESTED for循环的解决方案(蛮力方式),但是您要避免这种情况,因为时间复杂度很差O(n ^ 2)

注意:

.includes()您可以使用而不是像其他人那样使用 .indexOf()。如果您只是检查该值是否大于0。如果该值不存在,则会得到-1。如果确实存在,它将为您提供大于0的值。

indexOf()vs include()

哪一个性能更好?indexOf()有点,但我认为其中的内容更具可读性。

如果我没有记错,.includes()并且indexOf()在后台使用循环,那么将它们与一起使用时,您将处在O(n ^ 2)处.some()

使用循环

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

使用.some()

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

使用MAPS 时间复杂度 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专家,所以如果我说错了,请告诉我。


3

结合使用some / 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;
}

注意:如果您想对谓词做一些事情,可以将内部indexOf替换为另一个findIndex和谓词


3

我的解决方案使用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;


有什么方法可以从originalFruits中获取包含项的索引?
安齐尔·卡恩,

3

只是一种解决方案

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

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

var result = a1.filter(e => a2.indexOf(e) !== -1).length === a2.length
console.log(result)

2

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

尝试这个:

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的演示


2

使用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

2
就个人而言,尽管我喜欢underscorejs,但这是一个令人费解的代码外观的经典示例。不仅很难理解为下划线js代码,而且从一般的编码角度来看,也是如此(例如,当我想在数组中查找某物的索引时,“ every”一词就不会引起人们的注意。 “ indexOf”)。当额外增加几个字符时,我们可以避免不必要地使用第三方工具,从而可以提供纯JavaScript解决方案。为此,使用underscorejs意味着您的解决方案与第三方代码紧密结合。
csharpforevermore

@csharpforevermore我想这是一个品味问题,您说这个解决方案比其他所有解决方案都更复杂indexOf我认为相反:)。另一方面,我同意在不真正不需要外部库的情况下尝试不添加外部库,但是我并不是很着迷,第三方库不仅提供有用的功能,而且还提供可靠的功能。例如:您是否已使用解决方案测试了所有边缘情况和市长浏览器?..(顺便说一句,every不是在列表中查找索引,而是在列表中的每个元素中求值)
fguillen

2

添加到数组原型

免责声明:许多人强烈建议不要这样做。唯一真正的问题是,库是否添加了具有相同名称(行为不同)或类似名称的原型函数。

码:

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

2

带有部分匹配且不区分大小写的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)
            )
        )
}
//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"]

当您要提供一个搜索框,用户可以在其中键入单词,并且结果可以按任何顺序,位置和大小写包含这些单词时,此功能很有用。


2

更新@Paul Grimshaw答案,使用includesinsteed以indexOf获得更多可读性

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


1

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

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

0

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

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

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


2
当元素位于数组的开头或结尾或以其他顺序排列时,此方法将无效。
DanielM

1
-1是因为正如DanielM所说的那样。您可以在arrayAsString前面加上一个逗号作为解决方法,但是说实话,使用字符串似乎是一个过于复杂的解决方案。
JHH

0

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

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

有没有一种方法可以“清理”阵列?像删除第二个数组中的值(如果它们存在于第一个中一样)?
sandrooco

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

0
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;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.