Проверьте, содержит ли массив какой-либо элемент другого массива в JavaScript
У меня есть целевой массив ["apple","banana","orange"]
, и я хочу проверить, содержат ли другие массивы какие-либо из элементов целевого массива.
Например:
["apple","grape"] //returns true;
["apple","banana","pineapple"] //returns true;
["grape", "pineapple"] //returns false;
Как я могу сделать это в JavaScript?
Ответы
Ответ 1
Ваниль 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(..)
оба возвращают истину, если данный аргумент присутствует в массиве.
Ответ 2
ваниль 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;
});
};
Ответ 3
Если вы не против использования 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]
Функция пересечения вернет новый массив с элементами, которые он сопоставил, а если не совпадает с ним, возвращает пустой массив.
Ответ 4
Если вам не требуется принуждение типа (из-за использования 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
существует в целевом объекте.
UPDATE:
Вот как бы я организовал его в функцию (с некоторыми незначительными изменениями ранее):
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;
}());
DEMO: 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 what the `!!` is for
}
return found;
};
DEMO: http://jsfiddle.net/5Lv9v/
Недостатком этого решения является то, что только числа и строки (и логические значения) могут использоваться (правильно), потому что значения (неявно) преобразуются в строки и задаются в качестве ключей к карте поиска. Это не совсем хорошо/возможно/легко сделано для нелитеративных значений.
Ответ 5
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
Ответ 6
Использование 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"]));
Ответ 7
Вы можете использовать lodash и делать:
_.intersection(originalTarget, arrayToCheck).length > 0
Установить пересечение выполняется для обеих коллекций, создавая массив одинаковых элементов.
Ответ 8
Я нашел этот короткий и сладкий синтаксис для соответствия всем или некоторым элементам между двумя массивами. Например
//ИЛИ операция. найдите, существует ли какой-либо из элементов array2 в массиве 1. Это вернется, как только будет первое совпадение, когда какой-то метод прерывается, когда функция возвращает TRUE
let array1 = ['a', 'b', 'c', 'd', 'e'], array2 = ['a', 'b'];
console.log(array2.some(ele => array1.includes(ele)));
//выводит TRUE
//И операция. найти, если все элементы array2 существуют в array1. Это вернется, как только нет первого совпадения, когда какой-то метод прерывается, когда функция возвращает TRUE
let array1 = ['a', 'b', 'c', 'd', 'e'], array2 = ['a', 'x'];
console.log(!array2.some(ele => !array1.includes(ele)));
//печатает FALSE
Надеюсь, что это поможет кому-то в будущем!
Ответ 9
Вы можете использовать вложенный вызов Array.prototype.some. Это имеет то преимущество, что оно будет залогом в первом матче вместо других решений, которые будут выполняться через полный вложенный цикл.
например.
var arr = [1, 2, 3];
var match = [2, 4];
var hasMatch = arr.some(a => match.some(m => a === m));
Ответ 10
Как насчет использования комбинации некоторых /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 и предикат
Ответ 11
Мое решение использует помощники массивов Array.prototype.some() и Array.prototype.include(), которые также выполняют свою работу довольно эффективно.
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;
Ответ 12
Это можно сделать, просто выполнив итерацию по основному массиву и проверив, содержит ли другой массив какой-либо из целевого элемента или нет.
Попробуйте следующее:
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));
DEMO в JSFIDDLE
Ответ 13
С 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
Ответ 14
Добавление в массив прототипов
Отказ от ответственности:. Многие будут категорически против этого. Единственный раз, когда это действительно было проблемой, было то, что библиотека добавила функцию прототипа с тем же именем (которая вела себя по-другому) или что-то в этом роде.
Код:
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
Ответ 15
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"]));
Ответ 16
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"]
Это полезно, если вы хотите предоставить окно поиска, в котором пользователи могут вводить слова и результаты, могут иметь эти слова в любом порядке, положении и случае.
Ответ 17
Обновление @Paul Гримшоу ответ, использование includes
insteed из indexOf
для более читаемым
пусть найдено = arr1.some(r => arr2.indexOf(r)> = 0)
найдем = arr1.some(r => arr2.includes(r))
Ответ 18
Вот интересный случай, я думал, что должен поделиться.
Скажем, у вас есть массив объектов и массив выбранных фильтров.
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'] }
// ]
Ответ 19
Я придумал решение в node с помощью подчеркивания js следующим образом:
var checkRole = _.intersection(['A','B'], ['A','B','C']);
if(!_.isEmpty(checkRole)) {
next();
}
Ответ 20
Решение 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) );
Надеюсь, будет полезно.
Ответ 21
Лично я использовал бы следующую функцию:
var arrayContains = function(array, toMatch) {
var arrayAsString = array.toString();
return (arrayAsString.indexOf(','+toMatch+',') >-1);
}
Метод toString() всегда будет использовать запятые для разделения значений. Будет работать только с примитивными типами.
Ответ 22
Array.filter() с вложенным вызовом .find() вернет все элементы в первом массиве, которые являются членами второго массива. Проверьте длину возвращаемого массива, чтобы определить, был ли какой-либо из второго массива в первом массиве.
getCommonItems(firstArray, secondArray) {
return firstArray.filter((firstArrayItem) => {
return secondArray.find((secondArrayItem) => {
return firstArrayItem === secondArrayItem;
});
});
}
Ответ 23
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);
Ответ 24
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;
Ответ 25
Еще одно решение
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)