Verifique se uma matriz contém qualquer elemento de outra matriz em JavaScript

Eu tenho uma matriz de destino ["apple","banana","orange"] , e quero verificar se outras matrizes contêm qualquer um dos elementos da matriz de destino.

Por exemplo:

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

Como posso fazer isso em JavaScript?

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

Única linha: Baunilha JS

ES2016:

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

ES6:

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

Como funciona

Array.prototype.some(..) verifica cada elemento do array em relação a uma function de teste e retorna true se algum elemento do array passar a function de teste, caso contrário, retorna false. indexOf(..) >= 0 e includes(..) ambos retornam true se o argumento fornecido estiver presente na matriz.

Se você não se opuser a usar um libray, o http://underscorejs.org/ possui um método de interseção, que pode simplificar isso:

 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] 

A function de interseção retornará uma nova matriz com os itens correspondentes e, se não corresponder, retornará a matriz vazia.

Se você não precisa de coerção de tipo (por causa do uso de indexOf ), você pode tentar algo como o seguinte:

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

Onde arr contém os itens de destino. No final, found irá mostrar se o segundo array teve pelo menos uma partida contra o alvo.

Claro, você pode trocar números por qualquer coisa que você queira usar – strings são legais, como o seu exemplo.

E no meu exemplo específico, o resultado deve ser true porque o segundo array 3 existe no destino.


ATUALIZAR:

Aqui está como eu organizo isso em uma function (com algumas pequenas alterações de antes):

 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/

Nesse caso, a function poderia ser modificada para que o targetArray fosse passado como um argumento em vez de codificado permanentemente no fechamento.


UPDATE2:

Embora minha solução acima possa funcionar e ser (esperançosamente mais) legível, acredito que a maneira “melhor” de lidar com o conceito que descrevi é fazer algo um pouco diferente. O “problema” com a solução acima é que o indexOf dentro do loop faz com que a matriz de destino seja colocada em loop completamente para cada item na outra matriz. Isso pode ser facilmente “corrigido” usando uma “pesquisa” (um mapa … um literal de object JavaScript). Isso permite dois loops simples, sobre cada array. Aqui está um exemplo:

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

DEMO: http://jsfiddle.net/5Lv9v/

A desvantagem dessa solução é que somente números e strings (e booleanos) podem ser usados ​​(corretamente), porque os valores são (implicitamente) convertidos em strings e definidos como as chaves do mapa de pesquisa. Isso não é exatamente bom / possível / feito com facilidade para valores não literais.

Você poderia usar o lodash e fazer:

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

Definir interseção é feito em ambas as collections, produzindo uma matriz de elementos idênticos.

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

ES2016

 let a = ['a', 'b', 'c']; let b = ['c', 'a', 'd']; a.some(v => b.includes(v)); 

DEMO: https://jsfiddle.net/r257wuv5/

Eu encontrei esta syntax curta e doce para combinar todos ou alguns elementos entre dois arrays. Por exemplo

// operação OR. encontre se algum dos elementos array2 existe no array1. Isso retornará assim que houver uma primeira correspondência quando algum método for interrompido quando a function retornar TRUE

 let array1 = ['a', 'b', 'c', 'd', 'e'], array2 = ['a', 'b']; console.log(array2.some(ele => array1.includes(ele))); 

// imprime TRUE

// operação AND. encontre se todos os elementos array2 existem no array1. Isso retornará assim que não houver uma primeira correspondência quando algum método for interrompido quando a function retornar TRUE

 let array1 = ['a', 'b', 'c', 'd', 'e'], array2 = ['a', 'x']; console.log(!array2.some(ele => !array1.includes(ele))); 

// imprime FALSE

Espero que ajude alguém no futuro!

Que tal usar uma combinação de alguns / findIndex e indexOf?

Então, algo assim:

 var array1 = ["apple","banana","orange"]; var array2 = ["grape", "pineapple"]; var found = array1.some(function(v) { return array2.indexOf(v) != -1; }); 

Para torná-lo mais legível, você poderia adicionar essa funcionalidade ao próprio object 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; } 

Nota: Se você quiser fazer algo com um predicado, pode replace o indexOf interno por outro findIndex e um predicado.

Você pode usar uma chamada Array.prototype.some aninhada. Isso tem o benefício de ser liberado na primeira correspondência, em vez de outras soluções que serão executadas por todo o loop nested.

por exemplo.

 var arr = [1, 2, 3]; var match = [2, 4]; var hasMatch = arr.some(a => match.some(m => a === m)); 

Isso pode ser feito simplesmente fazendo uma iteração na matriz principal e verificando se outra matriz contém algum elemento de destino ou não.

Tente isto:

 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 no JSFIDDLE

Adicionando ao protótipo de matriz

Disclaimer: Muitos recomendariam fortemente contra isso. A única vez que realmente seria um problema era se uma biblioteca adicionasse uma function protótipo com o mesmo nome (que se comportasse de maneira diferente) ou algo parecido.

Código:

 Array.prototype.containsAny = function(arr) { return this.some( (v) => (arr.indexOf(v) >= 0) ) } 

Sem usar as funções de seta grande:

 Array.prototype.containsAny = function(arr) { return this.some(function (v) { return arr.indexOf(v) >= 0 }) } 

Uso

 var a = ["a","b"] console.log(a.containsAny(["b","z"])) // Outputs true console.log(a.containsAny(["z"])) // Outputs false 

Eu criei uma solução no nó usando sublinhado js assim:

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

Baunilha JS com correspondência parcial e insensível a maiúsculas e minúsculas

O problema com algumas abordagens anteriores é que elas exigem uma correspondência exata de cada palavra . Mas, e se você quiser fornecer resultados para correspondências parciais?

 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"] 

Isso é útil quando você deseja fornecer uma checkbox de pesquisa na qual os usuários digitam palavras e os resultados podem ter essas palavras em qualquer ordem, posição e caso.

Atualização resposta @Paul Grimshaw, use includes insteed de indexOf para mais legível

vamos encontrar = arr1.some (r => arr2.indexOf (r)> = 0)
vamos encontrar = arr1.some (r => arr2.includes (r))

Com 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 

Aqui está um caso interessante que eu pensei que deveria compartilhar.

Digamos que você tenha uma matriz de objects e uma matriz de filtros selecionados.

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

Para aplicar os filtros selecionados a essa estrutura, podemos

 if (filters.length > 0) arr = arr.filter(obj => obj.tags.some(tag => filters.includes(tag)) ); // [ // { id: 'x', tags: ['foo'] }, // { id: 'y', tags: ['foo', 'bar'] } // ] 

Pessoalmente, eu usaria a seguinte function:

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

O método “toString ()” sempre usará vírgulas para separar os valores. Só funcionará realmente com tipos primitivos.

Array .filter () com uma chamada aninhada para .find () retornará todos os elementos da primeira matriz que são membros da segunda matriz. Verifique o comprimento da matriz retornada para determinar se alguma segunda matriz estava na primeira matriz.

 getCommonItems(firstArray, secondArray) { return firstArray.filter((firstArrayItem) => { return secondArray.find((secondArrayItem) => { return firstArrayItem === secondArrayItem; }); }); } 
 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);