Come ottenere l'indice dell'oggetto dalla sua proprietà in JavaScript?


241

Ad esempio, ho:

var Data = [
  { id_list: 1, name: 'Nick', token: '312312' },
  { id_list: 2, name: 'John', token: '123123' },
]

Quindi, voglio ordinare / invertire questo oggetto name, ad esempio. E poi voglio ottenere qualcosa del genere:

var Data = [
  { id_list: 2, name: 'John', token: '123123' },
  { id_list: 1, name: 'Nick', token: '312312' },
]

E ora voglio conoscere l'indice dell'oggetto con proprietà name='John'per ottenere il valore del token proprietà.

Come risolvo il problema?


Perché vuoi ordinare l'elenco prima di cercare la proprietà?
JJJ,

Gli oggetti JavaScript sono {Key:Value}, l'ho risolto per te.
Rocket Hazmat,


Se si esegue la scansione delle risposte, sembra che ci sia un Dataoggetto nativo . È semplicemente un nome variabile maiuscolo, che è contro la convenzione. Se qualcun altro è infastidito da questo, apporterò modifiche alla domanda e alle risposte per correggere questa denominazione.
Roy Prins,

Risposte:


170

Come suggeriscono le altre risposte, il looping dell'array è probabilmente il modo migliore. Ma lo metterei nella sua funzione e lo renderei un po 'più astratto:

function findWithAttr(array, attr, value) {
    for(var i = 0; i < array.length; i += 1) {
        if(array[i][attr] === value) {
            return i;
        }
    }
    return -1;
}

var Data = [
    {id_list: 2, name: 'John', token: '123123'},
    {id_list: 1, name: 'Nick', token: '312312'}
];

Con questo, non solo puoi trovare quale contiene 'John' ma puoi trovare quale contiene il token '312312':

findWithAttr(Data, 'name', 'John'); // returns 0
findWithAttr(Data, 'token', '312312'); // returns 1
findWithAttr(Data, 'id_list', '10'); // returns -1

EDIT: funzione aggiornata per restituire -1 quando non trovato, quindi segue lo stesso costrutto di Array.prototype.indexOf ()


1
Aggiunta una risposta che estende questa per coprire la ricerca più in profondità di un livello di attributo. Grazie per questo Chris - mi ha davvero aiutato: D
Ed Shee,

3
A coloro che avranno problemi con questa soluzione, ricorda che il segno uguale === non controllerà solo il valore ma anche il tipo di dati. pertanto il confronto di data, numeri e valori vuoti potrebbe restituire false se il valore effettivo è una stringa. Puoi usare == segno uguale se il tipo di dati non è essenziale per te.
David Addoteye,

NON FARE QUESTO. Scopri come utilizzare le funzioni di ordine superiore, questo è il vecchio modo di fare le cose.
Led

327

Poiché la parte di ordinamento ha già ricevuto risposta. Proporrò solo un altro modo elegante per ottenere l'indice di una proprietà nel tuo array

Il tuo esempio è:

var Data = [
    {id_list:1, name:'Nick',token:'312312'},
    {id_list:2,name:'John',token:'123123'}
]

Tu puoi fare:

var index = Data.map(function(e) { return e.name; }).indexOf('Nick');

Array.prototype.mapnon è disponibile su IE7 o IE8. Compatibilità ES5

Ed eccolo qui con ES6 e la sintassi della freccia, che è ancora più semplice:

const index = Data.map(e => e.name).indexOf('Nick');

4
Devo iterare l'intero array, qualunque cosa accada. Il primo metodo non è necessario.
Attanasio tedesco,

1
Semplice, ma
tieni

1
La risposta davvero eccezionale mi ha aiutato con questo problema!
NiallMitch14,

1
Questa soluzione è adorabile. Possa lei vivere per avere mille anni, signore.
deepelement

3
Fare una mappa e quindi indexOf nella versione ES6 significa che eseguiranno il loop sull'array due volte. Invece dovresti usare il metodo findIndex mostrato nella mia risposta
silverlight513

209

Se stai bene usando ES6. Gli array ora hanno la funzione findIndex . Ciò significa che puoi fare qualcosa del genere:

const index = Data.findIndex(item => item.name === 'John');

6
senza dubbio la soluzione più diretta ed elegante, farei un piccolo non che findIndex è avido - nel mio caso è stato perfetto - ma gli utenti devono essere consapevoli del fatto che se si hanno oggetti con valori duplicati (cioè due oggetti con name: John) questo restituirà solo la prima partita
GrayedFox,

Eccezionale!! Grazie.
moreirapontocom

@GrayedFox non intendevi NON avido? Greedy significa più risultati e findIndex restituisce solo la prima corrispondenza.
Jos,

1
Scusa @Jos ma penso che tu non capisca esattamente cosa fa un avido algoritmo di ricerca . Un algoritmo avido considera solo le informazioni che ha a portata di mano, che è computazionalmente efficiente per, diciamo, cercare un elemento in un elenco quando hai bisogno di un solo risultato. Il metodo findIndex è avido in modo preciso perché restituisce solo la prima corrispondenza. Se non fosse avido, continuerebbe a cercare. Stai pensando al termine "goloso" come viene usato nell'inglese quotidiano, ma nel contesto della programmazione (cioè SO), è l'opposto di quello che pensi;)
GrayedFox,

Grazie per aver spiegato @GrayedFox. Il mio riferimento al goloso era in realtà anche dalla programmazione, ma era collegato ad espressioni regolari in cui il goloso prende più personaggi che non avidi! :-)
Jos

28
var index = Data.findIndex(item => item.name == "John")

Che è una versione semplificata di:

var index = Data.findIndex(function(item){ return item.name == "John"})

Da mozilla.org:

Il metodo findIndex () restituisce l'indice del primo elemento dell'array che soddisfa la funzione di test fornita. Altrimenti viene restituito -1.


2
Usa "===" per il confronto delle stringhe è l'unica cosa che manca in questa risposta.
Bruno Tavares,

@BrunoTavares, quale scenario pensi che sarebbe diverso in questo caso?
edank,

1
@edank Se OP dovesse controllare il tokencampo invece del namecampo potrebbero esserci problemi, come Data[0].token == 312312valuta true, ma Data[0].token === 321321valuta false.
kem

@edank dai un'occhiata a questa risposta stackoverflow.com/questions/359494/…
Bruno Tavares,

23

Se riscontri problemi con IE, puoi utilizzare la funzione map () che è supportata dalla 9.0 in poi:

var index = Data.map(item => item.name).indexOf("Nick");

1
La risposta di seguito fornisce ulteriori informazioni ed è stata pubblicata per prima.
Alexander

Questa è sicuramente la soluzione migliore per questo.
Bebolicious

4

L'unico modo per me noto è quello di eseguire il looping di tutti gli array:

var index=-1;
for(var i=0;i<Data.length;i++)
  if(Data[i].name==="John"){index=i;break;}

o maiuscole / minuscole:

var index=-1;
for(var i=0;i<Data.length;i++)
  if(Data[i].name.toLowerCase()==="john"){index=i;break;}

Al risultato, l' indice variabile contiene l'indice dell'oggetto o -1 se non trovato.


2

un modo prototipico

(function(){
  if (!Array.prototype.indexOfPropertyValue){
    Array.prototype.indexOfPropertyValue = function(prop,value){
      for (var index = 0; index < this.length; index++){
        if (this[index][prop]){
          if (this[index][prop] == value){
            return index;
          }
        }
      }
      return -1;
    }
  }
 })();
 // usage:
 var Data = [
 {id_list:1, name:'Nick',token:'312312'},{id_list:2,name:'John',token:'123123'}];
 Data.indexOfPropertyValue('name','John'); // returns 1 (index of array);
 Data.indexOfPropertyValue('name','Invalid name') // returns -1 (no result);
 var indexOfArray = Data.indexOfPropertyValue('name','John');
 Data[indexOfArray] // returns desired object.

Ho dovuto cambiarlo un po 'per funzionare in base alla mia situazione: stavo cercando l'indice di una proprietà con un valore null e la quinta riga faceva sì che questo ignorasse quell'indice.
David Brunow,

1

È possibile utilizzare Array.sort utilizzando una funzione personalizzata come parametro per definire il meccanismo di ordinamento.

Nel tuo esempio, darebbe:

var Data = [
    {id_list:1, name:'Nick',token:'312312'},{id_list:2,name:'John',token:'123123'}
]

Data.sort(function(a, b){
    return a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
});

alert("First name is : " + Data[0].name); // alerts 'John'
alert("Second name is : " + Data[1].name); // alerts 'Nick'

La funzione di ordinamento deve restituire -1 se a deve precedere b, 1 se a deve venire dopo be 0 se entrambi sono uguali. Sta a te definire la logica giusta nella tua funzione di ordinamento per ordinare l'array.

Modifica: manca l'ultima parte della domanda in cui si desidera conoscere l'indice. Dovresti passare in rassegna l'array per scoprirlo come altri hanno già detto.


1

Basta passare attraverso l'array e trovare la posizione:

var i = 0;
for(var item in Data) {
    if(Data[item].name == 'John')
        break;
    i++;
}
alert(i);

Questo dovrebbe essere if(Data[item].name == 'John'), l'ho risolto per te.
Rocket Hazmat,

Questo ha un momento. Se 'non trovato' variabile i contengono indice positivo. E per testare "non trovato" bisogna confrontare se i === Data.length
Andrew D.

Il secondo momento è se l'array contiene proprietà personalizzate non indicizzate. Ad esempio: var Data [1,2,3,4,5]; Dati [ "test"] = 7897; Confronta l'output di: for (var i in Data) alert (Data [i]); e per (var i = 0; i <Data.length; i ++) alert (Data [i]);
Andrew D.


1

Perché non usi una piccola soluzione?

Crea un nuovo array con nomi come indici. dopodiché tutte le ricerche utilizzeranno gli indici. Quindi, solo un loop. Dopodiché non è necessario passare in rassegna tutti gli elementi!

var Data = [
    {id_list:1, name:'Nick',token:'312312'},{id_list:2,name:'John',token:'123123'}
    ]
var searchArr = []
Data.forEach(function(one){
  searchArr[one.name]=one;
})
console.log(searchArr['Nick'])

http://jsbin.com/xibala/1/edit

esempio dal vivo.


Ciò significa eseguire prima il looping di tutto ... quindi modificare gli oggetti (a meno che non vengano clonati ma ciò è ancora più elevato). E dopo quello fai di nuovo il loop (almeno in parte).
Jos,

1

Estesa la risposta di Chris Pickett perché nel mio caso avevo bisogno di cercare più in profondità di un livello di attributo:

function findWithAttr(array, attr, value) {
  if (attr.indexOf('.') >= 0) {
    var split = attr.split('.');
    var attr1 = split[0];
    var attr2 = split[1];
    for(var i = 0; i < array.length; i += 1) {
      if(array[i][attr1][attr2] === value) {
        return i;
      }
    }
  } else {
    for(var i = 0; i < array.length; i += 1) {
      if(array[i][attr] === value) {
        return i;
      }
    }
  };
};

È possibile passare 'attr1.attr2' nella funzione


1

Che dire di questo ? :

Data.indexOf(_.find(Data, function(element) {
  return element.name === 'John';
}));

Supponendo che tu stia usando lodash o underscorejs.


1
var fields = {
teste:
{
    Acess:
    {
        Edit: true,
      View: false

      }
 },
teste1:
{
    Acess:
    {
        Edit: false,
      View: false

      }
  }
};

console.log(find(fields,'teste'));
function find(fields,field){
    for(key in fields){
        if(key == field){
        return true;
    }
}
return false;
}

Se hai un oggetto con moltiplicare gli oggetti all'interno, se vuoi sapere se alcuni oggetti sono inclusi nell'oggetto Master, basta mettere find (MasterObject, 'Object to Search'), questa funzione restituirà la risposta se esiste o no (TRUE o FALSE ), Spero di esserti di aiuto, posso vedere l'esempio su JSFiddle .


Aggiungi una spiegazione con la risposta su come questa risposta aiuta OP nel risolvere il problema attuale
ρяσѕρєя K

@ ρяσѕρєяK, Grazie per il tuo suggerimento, ho già aggiunto la spiegazione :)
Pedro Monteiro Arantes,

1
let indexOf = -1;
let theProperty = "value"
let searchFor = "something";

theArray.every(function (element, index) {

    if (element[theProperty] === searchFor) {
        indexOf = index;
        return false;
    }
    return true;
});

1
collection.findIndex(item => item.value === 'smth') !== -1

Sebbene questo frammento di codice possa risolvere la domanda, inclusa una spiegazione aiuta davvero a migliorare la qualità del tuo post. Ricorda che stai rispondendo alla domanda per i lettori in futuro e quelle persone potrebbero non conoscere i motivi del tuo suggerimento sul codice. Cerca inoltre di non aggiungere il tuo codice a commenti esplicativi, in quanto ciò riduce la leggibilità sia del codice che delle spiegazioni!
Arrivederci StackExchange il

1

Se si desidera ottenere il valore del token di proprietà, è possibile provare anche questo

    let data=[
      { id_list: 1, name: 'Nick', token: '312312' },
      { id_list: 2, name: 'John', token: '123123' },
    ]

    let resultingToken =  data[_.findKey(data,['name','John'])].token

dove _.findKey è la funzione di lodash


0

In alternativa alla risposta tedesca di Attanasio Ruiz, puoi eliminare il 2o ciclo usando Array.reduce () invece di Array.map ();

var Data = [
    { name: 'hypno7oad' }
]
var indexOfTarget = Data.reduce(function (indexOfTarget, element, currentIndex) {
    return (element.name === 'hypno7oad') ? currentIndex : indexOfTarget;
}, -1);

-1

Utilizzando il trattino basso:

var index = _.indexOf(_.pluck(item , 'name'), 'Nick');
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.