Obtener el índice del objeto dentro de una matriz, cumpliendo una condición

Resuelto amp asked hace 11 años • 14 respuestas

Tengo una matriz como esta:

[{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"},...]

¿Cómo puedo obtener el índice del objeto que coincide con una condición, sin iterar sobre toda la matriz?

Por ejemplo, dado prop2=="yutu", quiero obtener el índice 1.

Lo vi, .indexOf()pero creo que se usa para matrices simples como ["a1","a2",...]. También lo verifiqué $.grep()pero esto devuelve objetos, no el índice.

amp avatar Apr 14 '13 17:04 amp
Aceptado

A partir de 2016, se supone que debes usar Array.findIndex(un estándar ES2015/ES6) para esto:

a = [
  {prop1:"abc",prop2:"qwe"},
  {prop1:"bnmb",prop2:"yutu"},
  {prop1:"zxvz",prop2:"qwrq"}];
    
index = a.findIndex(x => x.prop2 ==="yutu");

console.log(index);
Expandir fragmento

Es compatible con Google Chrome, Firefox y Edge. Para Internet Explorer, hay un polyfill en la página vinculada.

Nota de rendimiento

Las llamadas a funciones son costosas, por lo tanto, con matrices realmente grandes, un bucle simple funcionará mucho mejor que findIndex:

let test = [];

for (let i = 0; i < 1e6; i++)
    test.push({prop: i});


let search = test.length - 1;
let count = 100;

console.time('findIndex/predefined function');
    let fn = obj => obj.prop === search;

    for (let i = 0; i < count; i++)
        test.findIndex(fn);
console.timeEnd('findIndex/predefined function');


console.time('findIndex/dynamic function');
    for (let i = 0; i < count; i++)
        test.findIndex(obj => obj.prop === search);
console.timeEnd('findIndex/dynamic function');


console.time('loop');
    for (let i = 0; i < count; i++) {
        for (let index = 0; index < test.length; index++) {
            if (test[index].prop === search) {
                break;
            }
        }
    }
console.timeEnd('loop');
Expandir fragmento

Como ocurre con la mayoría de las optimizaciones, esto debe aplicarse con cuidado y sólo cuando sea realmente necesario.

georg avatar Apr 14 '2013 10:04 georg

¿Cómo puedo obtener el índice del objeto que coincide con una condición (sin iterar a lo largo de la matriz)?

No se puede, algo tiene que recorrer la matriz (al menos una vez).

Si la condición cambia mucho, tendrás que recorrer y observar los objetos que contiene para ver si coinciden con la condición. Sin embargo, en un sistema con características ES5 (o si instala una corrección), esa iteración se puede realizar de manera bastante concisa:

var index;
yourArray.some(function(entry, i) {
    if (entry.prop2 == "yutu") {
        index = i;
        return true;
    }
});

Eso utiliza la Array#somefunción new(ish) , que recorre las entradas de la matriz hasta que la función que le asigna devuelve verdadero. La función que le he asignado guarda el índice de la entrada coincidente y luego regresa truepara detener la iteración.

O, por supuesto, simplemente use un forbucle. Sus diversas opciones de iteración se tratan en esta otra respuesta .

Pero si siempre va a utilizar la misma propiedad para esta búsqueda y si los valores de la propiedad son únicos, puede realizar un bucle solo una vez y crear un objeto para asignarlos:

var prop2map = {};
yourArray.forEach(function(entry) {
    prop2map[entry.prop2] = entry;
});

(O, nuevamente, podrías usar un forbucle o cualquiera de tus otras opciones ).

Luego, si necesita encontrar la entrada con prop2 = "yutu", puede hacer esto:

var entry = prop2map["yutu"];

A esto lo llamo "indexación cruzada" de la matriz. Naturalmente, si elimina o agrega entradas (o cambia sus prop2valores), también deberá actualizar su objeto de mapeo.

T.J. Crowder avatar Apr 14 '2013 10:04 T.J. Crowder

Lo que dijo TJ Crowder, siempre tendrá algún tipo de iteración oculta, con lodash esto se convierte en:

var index = _.findIndex(array, {prop2: 'yutu'})
aliak avatar Feb 03 '2015 13:02 aliak
var CarId = 23;

//x.VehicleId property to match in the object array
var carIndex = CarsList.map(function (x) { return x.VehicleId; }).indexOf(CarId);

Y para números de matriz básicos también puedes hacer esto:

var numberList = [100,200,300,400,500];
var index = numberList.indexOf(200); // 1

Obtendrá -1 si no puede encontrar un valor en la matriz.

David Castro avatar Aug 16 '2017 23:08 David Castro
var index;
yourArray.some(function (elem, i) {
    return elem.prop2 === 'yutu' ? (index = i, true) : false;
});

Iterar sobre todos los elementos de la matriz. Devuelve el índice y verdadero o falso si la condición no coincide.

Importante es el valor de retorno explícito de verdadero (o un valor cuyo resultado booleano sea verdadero). La asignación única no es suficiente, debido a un posible índice con 0 (Boolean(0) === false), que no resultaría en un error pero deshabilitaría la interrupción de la iteración.

Editar

Una versión aún más corta de lo anterior:

yourArray.some(function (elem, i) {
    return elem.prop2 === 'yutu' && ~(index = i);
});
Nina Scholz avatar Apr 08 '2015 17:04 Nina Scholz