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

Ale*_*lex 325 javascript arrays

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

例如:

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

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

["grape", "pineapple"] //returns false;
Run Code Online (Sandbox Code Playgroud)

我怎么能在JavaScript中做到这一点?

Pau*_*haw 419

香草JS

ES2016:

const found = arr1.some(r=> arr2.includes(r))
Run Code Online (Sandbox Code Playgroud)

ES6:

const found = arr1.some(r=> arr2.indexOf(r) >= 0)
Run Code Online (Sandbox Code Playgroud)

这个怎么运作

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

  • 这段代码需要一个解释 - 这可能有用,但没有价值,因为没有人学习任何东西 (31认同)
  • arr1 和 arr2 对于教学来说是糟糕的名字 (13认同)
  • Array.prototype.some()根据测试函数检查数组的每个元素,如果数组的任何元素通过测试函数,则返回"true".否则,它返回`false`. (6认同)
  • 这应该是正确的答案!伟大的使用ES6 (2认同)

sky*_*red 219

香草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;
    });
};
Run Code Online (Sandbox Code Playgroud)

  • 也可在ES2016中找到`arr.some(v => haystack.includes(v))` (79认同)
  • 好的解决方案 `some()`是rad.一旦匹配就退出. (9认同)
  • 事件整整像这样:`arr.some(v => haystack.indexOf(v)> = 0)` (6认同)
  • 在一行`arr1.some(v => arr2.indexOf(v)> = 0)`. (5认同)
  • 目前,最好避免使用 `includes`,因为 IE 显然不支持它:/sf/ask/2560204601/ (3认同)

wil*_*llz 70

如果你不反对使用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]
Run Code Online (Sandbox Code Playgroud)

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

  • 我已经多次使用过这个,但请注意问题是关于检查*if*是否存在另一个数组中的任何元素,而不是产生整个交集.在性能方面,如果阵列很大,则存在巨大差异,因为在第一种情况下,一旦找到一个匹配就可以拯救. (3认同)

lus*_*usk 42

ES6(最快)

const a = ['a', 'b', 'c'];
const b = ['c', 'a', 'd'];
a.some(v=> b.indexOf(v) !== -1)
Run Code Online (Sandbox Code Playgroud)

ES2016

const a = ['a', 'b', 'c'];
const b = ['c', 'a', 'd'];
a.some(v => b.includes(v));
Run Code Online (Sandbox Code Playgroud)

下划线

const a = ['a', 'b', 'c'];
const b = ['c', 'a', 'd'];
_.intersection(a, b)
Run Code Online (Sandbox Code Playgroud)

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

jsPerf:https://jsperf.com/array-contains-any-element-of-another-array

  • 这是最简单和声明性的解决方案 (2认同)

Ian*_*Ian 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);
Run Code Online (Sandbox Code Playgroud)

哪里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;
}());
Run Code Online (Sandbox Code Playgroud)

演示: 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;
};
Run Code Online (Sandbox Code Playgroud)

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

此解决方案的缺点是只能使用(正确)数字和字符串(和布尔值),因为值(隐式)转换为字符串并设置为查找映射的键.对于非文字值,这不是很好/可能/容易完成.

  • 非常好的例子,第二个例子简直太棒了. (2认同)

Ale*_*der 30

const areCommonElements = (arr1, arr2) => {
    const arr2Set = new Set(arr2);
    return arr1.some(el => arr2Set.has(el));
};
Run Code Online (Sandbox Code Playgroud)

或者,如果您首先找出这两个数组中的哪一个更长并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));
};
Run Code Online (Sandbox Code Playgroud)

  • 当人们不断发布带有嵌套 `indexOf` 和 `includes` 的解决方案时,您是第一个使用更高效的基于集合的解决方案(使用本机 `Set`)来回答的,距离它被引入 EcmaScript 已有 4 年了。+1 (4认同)

Vad*_*hev 28

使用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"]));
Run Code Online (Sandbox Code Playgroud)


小智 28

你可以使用lodash并做:

_.intersection(originalTarget, arrayToCheck).length > 0
Run Code Online (Sandbox Code Playgroud)

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


dev*_*ato 21

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

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

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

笔记:

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

indexOf() 与包含()

哪个性能更好?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;
    };
Run Code Online (Sandbox Code Playgroud)

使用 .some()

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

使用地图 时间复杂度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;
};
Run Code Online (Sandbox Code Playgroud)

我的代码: stackblitz

我不是表演专家,也不是 BigO,所以如果我说的有误,请告诉我。

  • 关于使用包含,我认为确定哪个数组更短/更长并不重要。看看“Array#includes”是如何实现的(tc39.es/ecma262/#sec-array.prototype.includes),看起来您仍然必须迭代较长的数组。除非我读到的“includes”的实现全部错误(这是可能的,哈哈)。另外,我同意使用地图是最有效的。 (2认同)

tan*_*993 10

ES6解决方案:

let arr1 = [1, 2, 3];
let arr2 = [2, 3];

let isFounded = arr1.some( ai => arr2.includes(ai) );
Run Code Online (Sandbox Code Playgroud)

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

let allFounded = arr2.every( ai => arr1.includes(ai) );
Run Code Online (Sandbox Code Playgroud)

希望会有所帮助。

  • 就我而言,只有从函数内部返回时它才有效,例如:`let allFounded = arr2.every( ai =&gt; return arr1.includes(ai) );` (2认同)

小智 9

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

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

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

console.log(array2.some(ele => array1.includes(ele)));
Run Code Online (Sandbox Code Playgroud)

//打印为TRUE

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

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

console.log(!array2.some(ele => !array1.includes(ele)));
Run Code Online (Sandbox Code Playgroud)

//打印FALSE

希望将来帮助某人!


Con*_*yen 8

还有一种解决方案

var a1 = [1, 2, 3, 4, 5]
var a2 = [2, 4]
Run Code Online (Sandbox Code Playgroud)

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

var result = a1.filter(e => a2.indexOf(e) !== -1).length === a2.length
console.log(result)
Run Code Online (Sandbox Code Playgroud)


It'*_*lex 6

使用 some/findIndex 和 indexOf 的组合怎么样?

所以像这样:

var array1 = ["apple","banana","orange"];
var array2 = ["grape", "pineapple"];

var found = array1.some(function(v) { return array2.indexOf(v) != -1; });
Run Code Online (Sandbox Code Playgroud)

为了使其更具可读性,您可以将此功能添加到 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;
}
Run Code Online (Sandbox Code Playgroud)

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


bin*_*les 6

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

例如。

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

var hasMatch = arr.some(a => match.some(m => a === m));
Run Code Online (Sandbox Code Playgroud)


Neo*_*ist 5

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

getCommonItems(firstArray, secondArray) {
  return firstArray.filter((firstArrayItem) => {
    return secondArray.find((secondArrayItem) => {
      return firstArrayItem === secondArrayItem;
    });
  });
}
Run Code Online (Sandbox Code Playgroud)


use*_*921 5

这是一个我认为应该分享的有趣案例。

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

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

const filters = ['foo'];
Run Code Online (Sandbox Code Playgroud)

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

if (filters.length > 0)
  arr = arr.filter(obj =>
    obj.tags.some(tag => filters.includes(tag))
  );

// [
//   { id: 'x', tags: ['foo'] },
//   { id: 'y', tags: ['foo', 'bar'] }
// ]
Run Code Online (Sandbox Code Playgroud)


zem*_*mil 5

性能好的解决方案:

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

const contains = (arr1, mainObj) => arr1.some(el => el in mainObj);
const includes = (arr1, mainObj) => arr1.every(el => el in mainObj);
Run Code Online (Sandbox Code Playgroud)

用法:

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
Run Code Online (Sandbox Code Playgroud)

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


Vas*_*kyi 5

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

  • 该解决方案给了我一个错误。然而 `const found = arr1.some(item =&gt; arr2.includes(item))` 工作完美 (6认同)