我有一个目标数组[“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中实现?
如果不需要类型强制(因为使用了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包含目标项。最后,find将显示第二个数组是否与目标至少匹配一次。
当然,您可以将数字换成任何您想要使用的东西-字符串很好,就像您的示例一样。
在我的具体示例中,结果应该为真,因为目标中存在第二个数组的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/
这种解决方案的缺点是,只能(正确地)使用数字和字符串(以及布尔值),因为这些值(隐式地)转换为字符串并设置为查找映射的键。对于非文字值,这不是很好/可能/容易做到的。
如果你不反对使用图书馆,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演示
带下划线js
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
香草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;
});
};
正如@loganofsmyth所指出的,您可以在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=>haystalk.includes(v));
如果要确定数组是否包含其他数组中的所有项,请将some()替换为every()或作为arr.every(v=>haystalk.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:
函数containsAny(源,目标){var result=source.filter(函数(项){return target.indexOf(项)>-1});返回(result.length>0);} //结果var fruits=[“苹果”、“香蕉”、“橙色”];console.log(包含任何(水果,[“苹果”,“葡萄”]);console.log(包含任何(水果,[“苹果”,“香蕉”,“菠萝”]);console.log(包含任何(水果,[“葡萄”,“菠萝”]);
就我个人而言,我会使用以下功能:
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
您可以使用lodash并执行以下操作:
_.intersection(originalTarget, arrayToCheck).length > 0
在两个集合上进行集合交集,生成一个相同元素的数组。
我在node中使用下划线js提出了一个解决方案,如下所示:
var checkRole = _.intersection(['A','B'], ['A','B','C']);
if(!_.isEmpty(checkRole)) {
next();
}
香草JS
2016年:
const found = arr1.some(r=> arr2.includes(r))
ES6:
const found = arr1.some(r=> arr2.indexOf(r) >= 0)
它的工作原理
一些(..)根据测试函数检查数组的每个元素,如果数组的任何元素通过测试函数,则返回true,否则返回false。如果数组中存在给定参数,indexOf(..)>=0和includes(..)都返回true。
嵌套调用.find()的Array.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)
2016年
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)
)
)
}
//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"]
当您希望提供一个搜索框,用户可以在其中键入单词,结果可以以任何顺序、位置和大小写显示这些单词时,这非常有用。
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以提高可读性
let found=arr1.some(r=>arr2.indexOf(r)>=0)let found=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)));
//打印TRUE
//AND运算。查找array1中是否存在所有array2元素。当函数返回TRUE时,当某些方法中断时,一旦没有第一个匹配,就会返回该值
let array1 = ['a', 'b', 'c', 'd', 'e'], array2 = ['a', 'x'];
console.log(!array2.some(ele => !array1.includes(ele)));
//打印FALSE
希望这对将来的人有所帮助!
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.proto原型.includes()数组助手,它们的工作效率也很高
ES6型const originalFruits=[“苹果”、“香蕉”、“橙子”];const fruits1=[“苹果”、“香蕉”、“菠萝”];const fruits2=[“葡萄”,“菠萝”];const commonFruits=(myFruitsArr,otherFruitsAr)=>{return myFruitsArr.some(fruit=>otherFruitsAr.includes(fruit))}console.log(commonFruits(originalFruits,fruits1))//返回true;console.log(commonFruits(originalFruits,fruits2))//返回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.length
console.log(result)
const areCommonElements = (arr1, arr2) => {
const arr2Set = new Set(arr2);
return arr1.some(el => arr2Set.has(el));
};
或者,如果您首先找出这两个数组中的哪一个更长,并对最长的数组进行设置,同时对最短的数组应用一些方法,您甚至可以获得更好的性能:
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个解决方案。本质上,他们也是这样做的。他们一变为真就变为真。我写了三个解决方案,只是为了展示三种不同的做事方式。现在,这取决于你更喜欢什么。您可以使用performance.now()检查一个或另一个解决方案的性能。在我的解决方案中,我还检查了哪个阵列最大,哪个阵列最小,以提高操作效率。
第三种解决方案可能不是最可爱的,但很有效。我决定添加它,因为在一些编码面试中,您不允许使用内置方法。
最后,当然。。。我们可以用2个NESTED for循环(蛮力方法)提出解决方案,但您希望避免这种情况,因为时间复杂度是坏的O(n^2)。
注:
您可以使用.indexOf()。如果您检查该值是否大于0。如果值不存在会给你-1。如果它确实存在,它会给你大于0。
indexOf()与includes()
哪个性能更好?indexOf()稍有不同,但我认为includes更可读。
如果我没弄错的话,.includes()和indexOf()在幕后使用循环,所以当它们与.some()一起使用时,您将处于O(n^2)。
USING循环
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;
};
我的代码:堆垛机
我既不是表演专家,也不是BigO,所以如果我说的有错,请告诉我。
不确定这在性能方面可能有多高效,但这就是我使用数组解构来保持一切美好和简短的原因:
const shareElements = (arr1, arr2) => {
const typeArr = [...arr1, ...arr2]
const typeSet = new Set(typeArr)
return typeArr.length > typeSet.size
}
由于集合不能有重复的元素,而数组可以,因此组合两个输入数组,将其转换为集合,并比较集合大小和数组长度将告诉您它们是否共享任何元素。
当我看你的答案时,我找不到我想要的答案。我自己做了一些事,我想和你分享。
只有当输入的单词(数组)正确时,它才为真。
函数包含(a,b){让计数器=0;对于(var i=0;i<b.length;i++){;如果(a.包括(b[i]))计数器++;}如果(counter==b.length)返回true;return false;}让main_array=['fo','bar','baz'];设sub_array_a=['fo','obar'];设sub_array_b=['fo','bar'];console.log(包含(main_array,sub_array_a));//返回falseconsole.log(包含(main_array,sub_array_b));//返回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 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
您可能会面临由in运算符检查的一些缺点(例如{}//=>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);
}
如果条件不满足(比如你在品牌中加入了“梅赛德斯”),那么“intersectionEvery”就不满足了——这将是错误的。
如果满足条件,它将把[“福特”、“大众”]列为区别,把[“起亚”、“奥迪”]列为了常见列表。
沙盒: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);
}
我们在这里寻找一些常见的品牌,但不一定全部。
它将把[“福特”、“大众”]列为不同品牌,把[“起亚”、“奥迪”]列为了共同品牌。
沙盒:https://jsfiddle.net/zkq9j3Lh/