我有一个目标数组 ["apple","banana","orange"]
,我想检查其他数组是否包含目标数组中的任何一个元素。
例如:
["apple","grape"] //returns true;
["apple","banana","pineapple"] //returns true;
["grape", "pineapple"] //returns false;
我该如何用JavaScript实现它?
我有一个目标数组 ["apple","banana","orange"]
,我想检查其他数组是否包含目标数组中的任何一个元素。
例如:
["apple","grape"] //returns true;
["apple","banana","pineapple"] //returns true;
["grape", "pineapple"] //returns false;
我该如何用JavaScript实现它?
ES2016:
const found = arr1.some(r=> arr2.includes(r))
工作原理
some(..)
会对数组的每个元素进行测试,并在数组中的任何元素通过测试函数时返回true,否则返回false。includes(..)
会在给定的参数存在于数组中时返回true。
[false, false, false]
而不是一个空数组 []
,这是否符合预期? - Batman.filter()
方法来获取适用于手头任务的行列表,并且 some()
方法非常有用。谢谢。var searchTerms = ['term1', 'term2', 'term3', 'term4'];
var results = csvRows.filter(row => searchTerms.some(value => row.column1.includes(value)));
- Chazt3n/**
* @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));
some()
很棒。一旦匹配到任何内容就停止搜索。 - averydevarr.some(v=> haystack.indexOf(v) >= 0)
。 - Paul Grimshawarr.some(v => haystack.includes(v))
。 - loganfsmytharr1.some(v => arr2.indexOf(v) >= 0)
。 - webjayincludes
,因为显然它在 IE 中不受支持:https://dev59.com/eVoV5IYBdhLWcg3wL8Ww - Shafique Jamallet arr1 = [1, 2, 3];
let arr2 = [2, 3];
let isFound = arr1.some( ai => arr2.includes(ai) );
let allFound = arr2.every( ai => arr1.includes(ai) );
let allFounded = arr2.every( ai => return arr1.includes(ai) );
- Fed Cvar _ = 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]
_.some()
结合使用,即_.some(_.intersection(target, fruit2))
。 - Quitch_.isEmpty(_.intersection(target, fruit2))
。感谢 @willz - Jose VelascoES6(最快)
const a = ['a', 'b', 'c'];
const b = ['c', 'a', 'd'];
a.some(v=> b.indexOf(v) !== -1)
ES2016
->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
如果您不需要类型强制转换(因为使用了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 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/
这种解决方案的缺点是只能正确使用数字和字符串(以及布尔值),因为这些值被(隐式地)转换为字符串并设置为查找表中的键。对于非文字值,这并不完全好/可能/容易实现。
undefined
...这就是!!
的作用” - 这是错误的。它将返回!
的布尔反义。 - AlienWebguyfunction 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
会继续比较以找到所有匹配项。这就像在只需要find
时使用filter
一样。 - Alexanderconst 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));
};
indexOf
和 includes
的解决方案,但你是第一个使用更高效的基于集合的解决方案回答问题的人,该方案使用了本地的 Set
,距其被引入 EcmaScript 已经有4年了。+1 - trincot我写了3个解决方案,本质上它们都是一样的。只要它们得到true
,它们就会立即返回true
。我写这3个解决方案只是为了展示3种不同的做法。现在,它取决于你更喜欢什么。你可以使用performance.now()来检查一个解决方案或另一个解决方案的性能。在我的解决方案中,我还检查哪个数组最大、哪个数组最小,以使操作更加高效。
第3个解决方案可能不是最好的,但它很有效率。我决定添加它,因为在某些编程面试中,你不被允许使用内置方法。
最后,当然……我们可以用两个嵌套的for循环(暴力方式)提出一种解决方案,但你要避免这样做,因为时间复杂度很差O(n^2)。
注:
与其他人使用
.includes()
不同,你可以使用.indexOf()
。如果你这样做只需检查值是否大于0。如果该值不存在,将给你-1。如果存在,则会给你大于0的值。
哪个更好的性能?indexOf()
略胜一筹,但是在我看来includes
更易读。
如果我没有错,.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;
};
使用 .some()
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方面的专家,所以如果我说错了什么,请让我知道。
Array#includes
的实现方式(tc39.es/ecma262/#sec-array.prototype.includes),它仍然看起来像你必须遍历更长的数组。除非我完全误读了includes
的实现方式(这是可能的哈哈)。此外,我同意使用maps会是最有效的方法。 - Molasses.some()
解决方案显示两个数组中相同的项? - Jonathin
for
循环遍历目标数组。如果每个元素都包含在当前数组中(使用current.indexOf(elem) !== -1
),那么它们都在其中。 - Blendertrue
或false
,那么你需要使用.filter()
:: JavaScript 算法:查找数组中不在另一个数组中的元素 - whoami - fakeFaceTrueSoul