Melhor maneira de descobrir se um item está em uma matriz JavaScript?

Qual é a melhor maneira de descobrir se um object está em uma matriz?

Essa é a melhor maneira que conheço:

function include(arr, obj) { for(var i=0; i<arr.length; i++) { if (arr[i] == obj) return true; } } include([1,2,3,4], 3); // true include([1,2,3,4], 6); // undefined 

A partir do ECMAScript 2016, você pode usar includes()

 arr.includes(obj); 

Se você quiser suportar o IE ou outros navegadores mais antigos:

 function include(arr,obj) { return (arr.indexOf(obj) != -1); } 

EDIT: Isso não funcionará no IE6, 7 ou 8 embora. A melhor solução é definir você mesmo se não estiver presente:

  1. Versão da Mozilla (ECMA-262):

      if (!Array.prototype.indexOf) { Array.prototype.indexOf = function(searchElement /*, fromIndex */) { "use strict"; if (this === void 0 || this === null) throw new TypeError(); var t = Object(this); var len = t.length >>> 0; if (len === 0) return -1; var n = 0; if (arguments.length > 0) { n = Number(arguments[1]); if (n !== n) n = 0; else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) n = (n > 0 || -1) * Math.floor(Math.abs(n)); } if (n >= len) return -1; var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); for (; k < len; k++) { if (k in t && t[k] === searchElement) return k; } return -1; }; } 
  2. Versão de Daniel James :

     if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (obj, fromIndex) { if (fromIndex == null) { fromIndex = 0; } else if (fromIndex < 0) { fromIndex = Math.max(0, this.length + fromIndex); } for (var i = fromIndex, j = this.length; i < j; i++) { if (this[i] === obj) return i; } return -1; }; } 
  3. versão de roosteronacid :

     Array.prototype.hasObject = ( !Array.indexOf ? function (o) { var l = this.length + 1; while (l -= 1) { if (this[l - 1] === o) { return true; } } return false; } : function (o) { return (this.indexOf(o) !== -1); } ); 

Se você estiver usando jQuery:

 $.inArray(5 + 5, [ "8", "9", "10", 10 + "" ]); 

Para mais informações: http://api.jquery.com/jQuery.inArray/

Primeiro, implemente indexOf em JavaScript para navegadores que ainda não o tenham. Por exemplo, veja os extras da matriz de Erik Arvidsson (também, o post do blog associado ). E então você pode usar indexOf sem se preocupar com o suporte ao navegador. Aqui está uma versão ligeiramente otimizada de sua implementação indexOf :

 if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (obj, fromIndex) { if (fromIndex == null) { fromIndex = 0; } else if (fromIndex < 0) { fromIndex = Math.max(0, this.length + fromIndex); } for (var i = fromIndex, j = this.length; i < j; i++) { if (this[i] === obj) return i; } return -1; }; } 

Ele foi alterado para armazenar o tamanho para que ele não precise procurar em todas as iterações. Mas a diferença não é enorme. Uma function de propósito menos geral pode ser mais rápida:

 var include = Array.prototype.indexOf ? function(arr, obj) { return arr.indexOf(obj) !== -1; } : function(arr, obj) { for(var i = -1, j = arr.length; ++i < j;) if(arr[i] === obj) return true; return false; }; 

Eu prefiro usar a function padrão e deixar esse tipo de micro-otimização para quando for realmente necessário. Mas se você está interessado em micro-otimização eu adaptei os benchmarks vinculados ao roosterononid nos comentários, para fazer benchmark em buscas em arrays . Eles são bem crus, porém, uma investigação completa testaria matrizes com diferentes tipos, diferentes comprimentos e encontrando objects que ocorrem em diferentes lugares.

Se a matriz não estiver classificada, não há realmente uma maneira melhor (além de usar o indexOf mencionado acima, que acho que equivale à mesma coisa). Se a matriz estiver classificada, você pode fazer uma pesquisa binária, que funciona assim:

  1. Escolha o elemento do meio da matriz.
  2. O elemento que você está procurando é maior que o elemento escolhido? Se assim for, você eliminou a metade inferior da matriz. Se não for, você eliminou a metade superior.
  3. Escolha o elemento do meio da metade restante da matriz e continue como na etapa 2, eliminando as metades da matriz restante. Eventualmente, você encontrará seu elemento ou não terá mais espaço para procurar.

A busca binária é executada no tempo proporcional ao logaritmo do comprimento da matriz, de modo que pode ser muito mais rápido do que observar cada elemento individual.

assumindo .indexOf() é implementado

 Object.defineProperty( Array.prototype,'has', { value:function(o, flag){ if (flag === undefined) { return this.indexOf(o) !== -1; } else { // only for raw js object for(var v in this) { if( JSON.stringify(this[v]) === JSON.stringify(o)) return true; } return false; }, // writable:false, // enumerable:false }) 

!!! não faça Array.prototype.has=function(){... porque você adicionará um elemento enumerável em cada array e js será quebrado.

 //use like [22 ,'a', {prop:'x'}].has(12) // false ["a","b"].has("a") // true [1,{a:1}].has({a:1},1) // true [1,{a:1}].has({a:1}) // false 

o uso da comparação de forças do 2º argumento (bandeira) por valor em vez de referência

Depende do seu propósito. Se você programar para a Web, evite indexOf , ele não é suportado pelo Internet Explorer 6 (muitos deles ainda usados!) Ou uso condicional:

 if (yourArray.indexOf !== undefined) result = yourArray.indexOf(target); else result = customSlowerSearch(yourArray, target); 

indexOf é provavelmente codificado em código nativo, então é mais rápido do que qualquer coisa que você possa fazer em JavaScript (exceto busca binária / dicotomia se a matriz for apropriada). Nota: é uma questão de gosto, mas eu faria um return false; no final da sua rotina, para retornar um verdadeiro booleano …

Aqui está um pouco de meta-conhecimento para você – se você quiser saber o que você pode fazer com um Array, verifique a documentação – aqui está a página do Array para o Mozilla

https://developer.mozilla.org/pt-BR/docs/JavaScript/Reference/Global_Objects/Array

Lá você verá referência ao indexOf, adicionado no Javascript 1.6

Uma maneira robusta de verificar se um object é uma matriz em JavaScript é detalhada aqui:

Aqui estão duas funções do framework xa.js que eu anexo a um utils = {} ‘container’. Isso deve ajudá-lo a detectar corretamente as matrizes.

 var utils = {}; /** * utils.isArray * * Best guess if object is an array. */ utils.isArray = function(obj) { // do an instanceof check first if (obj instanceof Array) { return true; } // then check for obvious falses if (typeof obj !== 'object') { return false; } if (utils.type(obj) === 'array') { return true; } return false; }; /** * utils.type * * Attempt to ascertain actual object type. */ utils.type = function(obj) { if (obj === null || typeof obj === 'undefined') { return String (obj); } return Object.prototype.toString.call(obj) .replace(/\[object ([a-zA-Z]+)\]/, '$1').toLowerCase(); }; 

Se você quiser verificar se um object está em uma matriz, eu também incluo este código:

 /** * Adding hasOwnProperty method if needed. */ if (typeof Object.prototype.hasOwnProperty !== 'function') { Object.prototype.hasOwnProperty = function (prop) { var type = utils.type(this); type = type.charAt(0).toUpperCase() + type.substr(1); return this[prop] !== undefined && this[prop] !== window[type].prototype[prop]; }; } 

E finalmente esta function in_array:

 function in_array (needle, haystack, strict) { var key; if (strict) { for (key in haystack) { if (!haystack.hasOwnProperty[key]) continue; if (haystack[key] === needle) { return true; } } } else { for (key in haystack) { if (!haystack.hasOwnProperty[key]) continue; if (haystack[key] == needle) { return true; } } } return false; }