Ottieni l'indice dell'oggetto all'interno di un array, corrispondente a una condizione


322

Ho un array come questo:

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

Come posso ottenere l'indice dell'oggetto che corrisponde a una condizione, senza iterare sull'intero array?

Ad esempio, dato prop2=="yutu", voglio ottenere l'indice 1.

Ho visto .indexOf()ma penso che sia usato per matrici semplici come ["a1","a2",...]. Ho anche controllato $.grep()ma questo restituisce oggetti, non l'indice.

Risposte:


733

A partire dal 2016, dovresti usare Array.findIndex(uno standard ES2015 / ES6) per questo:

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

console.log(index);

È supportato in Google Chrome, Firefox e Edge. Per Internet Explorer, c'è un polyfill nella pagina collegata.

Nota sulle prestazioni

Le chiamate di funzione sono costose, quindi con array molto grandi un semplice loop funzionerà molto meglio di 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');

Come con la maggior parte delle ottimizzazioni, questo dovrebbe essere applicato con cura e solo quando effettivamente necessario.


3
Non vedo la necessità di un array temporaneo qui. Basta usare il fatto che la funzione iteratore si chiude sul contesto e usare una variabile. Inoltre, la versione non jQuery non funziona (supponiamo che si trovi nell'indice 0?). Entrambe le soluzioni eseguono più iterazioni del necessario, il che è meno che ideale se l'array è grande (anche se le probabilità che sia così grande che un essere umano noterebbe sono basse, a meno che le ricerche non stiano accadendo molto ).
TJ Crowder,

@ thg435: Penso ancora che sia un po 'una macchina Rube Goldberg in cui una semplice leva farebbe il trucco. :-) Ma ehi, funziona!
TJ Crowder,

4
Puoi spiegare come x => x.prop2=="yutu"funziona con findIndex ()?
Abhay Pai,

5
@AbhayPai: è lo stesso difunction(x) { return x.prop2=="yutu" }
georg

6
Mi piace il suggerimento di usare il polyfill. Tuttavia, il codice come scritto non riesce ancora in IE11 anche con il polyfill a causa dell'uso di una funzione freccia / lambda. index = a.findIndex(function (x) { return x.prop2 == "yutu" })Riscritto come risolto il problema in modo che con il codice polyfill, findIndex funzionasse in IE11
Rick Glos,

26

Come posso ottenere l'indice dell'oggetto che corrisponde a una condizione (senza iterare lungo l'array)?

Non è possibile, qualcosa deve scorrere attraverso l'array (almeno una volta).

Se la condizione cambia molto, allora dovrai scorrere e guardare gli oggetti in essa contenuti per vedere se corrispondono alla condizione. Tuttavia, su un sistema con funzionalità ES5 (o se si installa uno shim), tale iterazione può essere eseguita in modo abbastanza conciso:

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

Che utilizza la nuova (ish) Array#somela funzione , che scorre le voci nella matrice finché la funzione si dà restituisce true. La funzione che ho assegnato salva l'indice della voce corrispondente, quindi ritorna trueper interrompere l'iterazione.

O ovviamente, basta usare un forloop. Le tue varie opzioni di iterazione sono trattate in questa altra risposta .

Ma se utilizzerai sempre la stessa proprietà per questa ricerca e se i valori delle proprietà sono univoci, puoi eseguire il ciclo solo una volta e creare un oggetto per mapparli:

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

(O, ancora, potresti usare un forloop o una qualsiasi delle tue altre opzioni .)

Quindi se devi trovare la voce con prop2 = "yutu", puoi farlo:

var entry = prop2map["yutu"];

Io chiamo questo "indicizzazione incrociata" dell'array. Naturalmente, se si rimuovono o si aggiungono voci (o si modificano i loro prop2valori), è necessario aggiornare anche l'oggetto di mappatura.


Grazie per la spiegazione! La soluzione con jQuery puntata ha thg435fatto quello che volevo ...
amp

21

Ciò che TJ Crowder ha detto, avrà comunque una sorta di iterazione nascosta, con lodash questo diventa:

var index = _.findIndex(array, {prop2: 'yutu'})

1
mentre puoi semplicemente passare in rassegna vari modi per ottenere l'indice, scopri che Index è la soluzione migliore, persino adottata in ES6 nei metodi di array nativi
Kelly Milligan,

13
var CarId = 23;

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

E per i numeri di array di base puoi anche fare questo:

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

Otterrai -1 se non riesce a trovare un valore nella matrice.


11
var index;
yourArray.some(function (elem, i) {
    return elem.prop2 === 'yutu' ? (index = i, true) : false;
});

Scorrere su tutti gli elementi dell'array. Restituisce l'indice e true o false se la condizione non corrisponde.

Importante è il valore di ritorno esplicito di true (o un valore il cui risultato booleano è true). L'assegnazione singola non è sufficiente, a causa di un possibile indice con 0 (Booleano (0) === falso), che non comporterebbe un errore ma disabilita l'interruzione dell'iterazione.

modificare

Una versione ancora più breve di quanto sopra:

yourArray.some(function (elem, i) {
    return elem.prop2 === 'yutu' && ~(index = i);
});

Cosa fa ~ character nel secondo snippet?
serkan,

@serkan, è un operatore NON bit| a bit , è una versione breve di ottenere da un indice (con -1) un risultato di verità / falsità , se esiste un indice.
Nina Scholz,

grazie Nina, senza il carattere ~, il codice funziona così com'è, no?
serkan,

@serkan, la tua domanda non è chiara, ma senza di ~essa non funziona così.
Nina Scholz,

1
oh, !!(index = 0)e !!~(index = 0)davvero la differenza. Grazie!
serkan,

4

È possibile utilizzare Array.prototype.some () nel modo seguente (come indicato nelle altre risposte):

https://jsfiddle.net/h1d69exj/2/

function findIndexInData(data, property, value) {
    var result = -1;
    data.some(function (item, i) {
        if (item[property] === value) {
            result = i;
            return true;
        }
    });
    return result;
}
var data = [{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"}]



alert(findIndexInData(data, 'prop2', "yutu")); // shows index of 1

4

Ho visto molte soluzioni in precedenza.

Qui sto usando la funzione map per trovare l'indice del testo di ricerca in un oggetto array.

Spiegherò la mia risposta usando i dati degli studenti.

  • passaggio 1 : creare un oggetto array per gli studenti (facoltativo è possibile creare il proprio oggetto array).
    var students = [{name:"Rambabu",htno:"1245"},{name:"Divya",htno:"1246"},{name:"poojitha",htno:"1247"},{name:"magitha",htno:"1248"}];

  • passaggio 2 : creare una variabile per cercare il testo
    var studentNameToSearch = "Divya";

  • passaggio 3 : creare una variabile per memorizzare l'indice corrispondente (qui utilizziamo la funzione mappa per iterare).
    var matchedIndex = students.map(function (obj) { return obj.name; }).indexOf(studentNameToSearch);

var students = [{name:"Rambabu",htno:"1245"},{name:"Divya",htno:"1246"},{name:"poojitha",htno:"1247"},{name:"magitha",htno:"1248"}];

var studentNameToSearch = "Divya";

var matchedIndex = students.map(function (obj) { return obj.name; }).indexOf(studentNameToSearch);

console.log(matchedIndex);

alert("Your search name index in array is:"+matchedIndex)


3
function findIndexByKeyValue(_array, key, value) {
    for (var i = 0; i < _array.length; i++) { 
        if (_array[i][key] == value) {
            return i;
        }
    }
    return -1;
}
var a = [
    {prop1:"abc",prop2:"qwe"},
    {prop1:"bnmb",prop2:"yutu"},
    {prop1:"zxvz",prop2:"qwrq"}];
var index = findIndexByKeyValue(a, 'prop2', 'yutu');
console.log(index);

1

Perché non vuoi iterare esattamente? Il nuovo Array.prototype.forEach è ottimo per questo scopo!

Se lo desideri, puoi utilizzare un albero di ricerca binario per trovare tramite una singola chiamata di metodo. Questa è un'implementazione ordinata dell'albero di ricerca BTree e Red black in JS - https://github.com/vadimg/js_bintrees - ma non sono sicuro che sia possibile trovare l'indice contemporaneamente.


1

Un passo usando Array.reduce () - no jQuery

var items = [{id: 331}, {id: 220}, {id: 872}];

var searchIndexForId = 220;
var index = items.reduce(function(searchIndex, item, index){
  if(item.id === searchIndexForId) { 
    console.log('found!');
    searchIndex = index;
  }
  return searchIndex;
}, null);

restituirà nullse l'indice non è stato trovato.


0
var list =  [
                {prop1:"abc",prop2:"qwe"},
                {prop1:"bnmb",prop2:"yutu"},
                {prop1:"zxvz",prop2:"qwrq"}
            ];

var findProp = p => {
    var index = -1;
    $.each(list, (i, o) => {
        if(o.prop2 == p) {
            index = i;
            return false; // break
        }
    });
    return index; // -1 == not found, else == index
}

0

Georg ha già menzionato che ES6 ha Array.findIndex per questo. E alcune altre risposte sono soluzioni alternative per ES5 utilizzando il metodo Array.some.

Un approccio più elegante può essere

var index;
for(index = yourArray.length; index-- > 0 && yourArray[index].prop2 !== "yutu";);

Allo stesso tempo, vorrei sottolineare, Array.some può essere implementato con binarie o altre tecniche di ricerca efficienti. Quindi, potrebbe funzionare meglio su loop in alcuni browser.


0

Prova questo codice

var x = [{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"}]
let index = x.findIndex(x => x.prop1 === 'zxvz')
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.