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

StackOverflow https://stackoverflow.com/questions/143847

  •  02-07-2019
  •  | 
  •  

Pergunta

Esta questão já tem uma resposta aqui:

Qual é a melhor maneira de descobrir se um objeto está em um array?

Esta é a melhor maneira que eu sei:

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
Foi útil?

Solução

A partir de ECMAScript 2016 você pode usar includes()

arr.includes(obj);

Se você quiser apoiar IE ou outros navegadores mais antigos:

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

EDIT: Isso não vai funcionar no IE6, 7 ou 8 embora. A melhor solução é defini-lo a si mesmo se não é presente:

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

      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. Daniel James 's versão:

    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. roosteronacid 's versão:

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

Outras dicas

Se você estiver usando jQuery:

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

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

Primeiro, implementar indexOf em JavaScript para navegadores que ainda não têm isso. Por exemplo, veja extras matriz Erik Arvidsson (também, a blogue associado pós ). E então você pode usar indexOf sem se preocupar com o suporte ao navegador. Aqui está uma versão ligeiramente otimizado 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 mudou para armazenar o comprimento de modo que ele não precisa procurá-lo cada iteração. Mas a diferença não é enorme. A função objetivo menos geral pode ser mais rápido:

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 função padrão e deixar este tipo de micro-otimização para quando é realmente necessário. Mas se você estiver interessado em micro-otimização I adaptou o benchmarks que roosterononacid ligada a nos comentários, para referência a pesquisa em matrizes . Eles são no entanto bastante crua, uma investigação completa iria testar matrizes com diferentes tipos, diferentes comprimentos e objetos encontrar que ocorrem em lugares diferentes.

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

  1. Escolha o elemento do meio da matriz.
  2. é o elemento que você está procurando maior do que o elemento que você escolheu? Se assim for, você eliminou a metade inferior da matriz. Se não for, você eliminou a metade superior.
  3. Pick o elemento do meio da metade restante da matriz, e continuar como no passo 2, eliminando as metades da matriz restante. Eventualmente você quer encontrar o seu elemento ou não têm variedade deixou de olhar através de.

binários corridas de busca em tempo proporcional ao logaritmo do comprimento da matriz, por isso pode ser muito mais rápido do que olhar para cada elemento individual.

[] .Tem (obj)

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 fazem Array.prototype.has=function(){... porque você vai adicionar um elemento enumeráveis ??em cada array e js está 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 de 2ª Arg (bandeira) forças comparation por valor em vez de referência

comparar objetos matérias

[o1].has(o2,true) // true if every level value is same

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

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

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

Eis alguns meta-conhecimento para você - se você quer saber o que você pode fazer com uma matriz, verifique a documentação - aqui está a página Array para Mozilla

https://developer.mozilla.org/en -US / docs / JavaScript / Referência / Global_Objects / matriz

Lá você verá referência a indexOf, acrescentou, em Javascript 1.6

Uma maneira robusta para verificar se um objeto é uma matriz em javascript está detalhado aqui:

Aqui estão duas funções do href="http://xajs.chalmershouse.com" rel="nofollow"> xa.js quadro que atribuo a um ‘recipiente’ utils = {}. Estes devem ajudá-lo a detectar corretamente arrays.

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ê então querer verificar se um objeto é em uma matriz, também gostaria de incluir 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 função 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;
}
scroll top