¿Cómo obtener el índice del objeto por su propiedad en JavaScript?

241

Por ejemplo, tengo:

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

Entonces, quiero ordenar / invertir este objeto name, por ejemplo. Y luego quiero obtener algo como esto:

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

Y ahora quiero saber el índice del objeto con propiedad name='John'para obtener el valor del token de propiedad.

¿Cómo resuelvo el problema?

rsboarder
fuente
¿Por qué desea ordenar la lista primero antes de buscar la propiedad?
JJJ
Los objetos de JavaScript son {Key:Value}, lo arreglé para ti.
Rocket Hazmat
Si escanea las respuestas, parece que hay algún Dataobjeto nativo . Es simplemente un nombre de variable en mayúscula, que está en contra de la convención. Si alguien más está molesto por esto, haré modificaciones a la pregunta y las respuestas para corregir este nombre.
Roy Prins
Pregunta relacionada: stackoverflow.com/questions/10557486/…
Anton Tarasenko

Respuestas:

170

Como sugieren las otras respuestas, recorrer la matriz es probablemente la mejor manera. Pero lo pondría en su propia función y lo haría un poco más abstracto:

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 esto, no solo puede encontrar cuál contiene 'John' sino que también puede encontrar cuál contiene el token '312312':

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

EDITAR: Función actualizada para devolver -1 cuando no se encuentra, por lo que sigue la misma construcción que Array.prototype.indexOf ()

Chris Pickett
fuente
1
Se agregó una respuesta que extiende esto para cubrir búsquedas más profundas que un nivel de atributo. Gracias por esto Chris - realmente ayudó: D
Ed Shee
3
Para aquellos que tendrán problemas con esta solución, recuerden que el signo igual === no solo verificará el valor sino también el tipo de datos. por lo tanto, la comparación de la fecha, los números y los valores vacíos pueden devolver falso si el valor real es una cadena. Puede usar == signo igual si el tipo de datos no es esencial para usted.
David Addoteye
NO HAGAS ESTO. Aprenda a usar funciones de orden superior, esta es la forma antigua de hacer las cosas.
Led
327

Dado que la parte de clasificación ya está respondida. Solo voy a proponer otra forma elegante de obtener el índice de una propiedad en su matriz

Tu ejemplo es:

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

Tu puedes hacer:

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

Array.prototype.mapno está disponible en IE7 o IE8. Compatibilidad con ES5

Y aquí está con ES6 y sintaxis de flecha, que es aún más simple:

const index = Data.map(e => e.name).indexOf('Nick');
Attanasio alemán
fuente
44
Tengo que iterar toda la matriz sin importar qué. El primer método no necesita hacerlo.
Attanasio alemán
1
Simple, pero tenga en cuenta el rendimiento al usar grandes conjuntos de datos
gavioto
1
Realmente gran respuesta me ayudó con este problema!
NiallMitch14
1
Esta solución es encantadora. Que viva hasta los mil años, señor.
profundización
3
Hacer un mapa y luego indexOf en la versión ES6 significa que se repetirán en la matriz dos veces. En su lugar, debe utilizar el método findIndex que se muestra en mi respuesta
silverlight513
209

Si estás de acuerdo con el uso de ES6. Las matrices ahora tienen la función findIndex . Lo que significa que puedes hacer algo como esto:

const index = Data.findIndex(item => item.name === 'John');
silverlight513
fuente
66
Sin duda, la solución más directa y elegante, haría un pequeño no es que findIndex sea codicioso, en mi caso fue perfecto, pero los usuarios deben saber que si tiene objetos con valores duplicados (es decir, dos objetos con name: John) esto solo devolverá el primer partido
GrayedFox
¡¡Increíble!! Gracias.
moreirapontocom
@GrayedFox ¿no querías decir NO codicioso? Codicioso significa más resultados y findIndex devuelve solo la primera coincidencia.
Jos
1
Lo siento @Jos, pero creo que no entiendes lo que hace un codicioso algoritmo de búsqueda . Un algoritmo codicioso considera solo la información que tiene a la mano, que es computacionalmente eficiente para, por ejemplo, buscar un elemento en una lista cuando solo necesita un resultado. El método findIndex es codicioso porque devuelve solo la primera coincidencia. Si no fuera codicioso, continuaría buscando. Estás pensando en el término "codicioso", ya que se usa en el inglés del día a día, pero en el contexto de la programación (es decir, SO), es lo contrario de lo que piensas;)
GrayedFox
Gracias por explicar @GrayedFox. ¡Mi referencia a codicioso era en realidad de la programación también, pero estaba relacionado con expresiones regulares donde codicioso toma más personajes que no codiciosos! :-)
Jos
28
var index = Data.findIndex(item => item.name == "John")

Cuál es una versión simplificada de:

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

Desde mozilla.org:

El método findIndex () devuelve el índice del primer elemento de la matriz que satisface la función de prueba proporcionada. De lo contrario, se devuelve -1.

edank
fuente
2
Use "===" para la comparación de cadenas, es lo único que falta en esta respuesta.
Bruno Tavares
@BrunoTavares, ¿qué escenario crees que sería diferente en este caso?
edank
1
@edank Si OP revisara el tokencampo en lugar del namecampo, podría haber problemas, como se Data[0].token == 312312evalúa true, pero se Data[0].token === 321321evalúa como false.
kem
@edank eche un vistazo en esta respuesta stackoverflow.com/questions/359494/…
Bruno Tavares
23

Si tiene problemas con IE, puede usar la función map () que es compatible desde 9.0 en adelante:

var index = Data.map(item => item.name).indexOf("Nick");
Alain T.
fuente
1
La respuesta a continuación proporciona más información y se publicó primero.
Alexander
Esta es definitivamente la mejor solución para esto.
Bebolicious
4

La única forma conocida para mí es recorrer toda la matriz:

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

o mayúsculas y minúsculas:

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

En el resultado, el índice variable contiene el índice del objeto o -1 si no se encuentra.

Andrew D.
fuente
2

una forma prototípica

(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.
Patrik Wallin
fuente
Tuve que cambiar esto un poco para que funcionara para mi situación: estaba buscando el índice de una propiedad con un valor nulo y la quinta línea estaba causando que esto saltara ese índice.
David Brunow
1

Puede usar Array.sort usando una función personalizada como parámetro para definir su mecanismo de clasificación.

En su ejemplo, daría:

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 función de clasificación debe devolver -1 si a debe venir antes que b, 1 si a debe venir después de b y 0 si ambos son iguales. Depende de usted definir la lógica correcta en su función de clasificación para ordenar la matriz.

Editar: se perdió la última parte de su pregunta donde desea conocer el índice. Tendría que recorrer la matriz para encontrar eso como otros han dicho.


fuente
1

Simplemente revise su matriz y encuentre la posición:

var i = 0;
for(var item in Data) {
    if(Data[item].name == 'John')
        break;
    i++;
}
alert(i);
Sascha Galley
fuente
Esto debería ser if(Data[item].name == 'John'), lo arreglé para ti.
Rocket Hazmat
Esto tiene un momento. Si 'no encontrado' variable i contengo índice positivo. Y para probar 'no encontrado' necesita comparar si i === Data.length
Andrew D.
El segundo momento es si la matriz contiene propiedades personalizadas no indexadas. Por ejemplo: var Data [1,2,3,4,5]; Datos ["prueba"] = 7897; Compare la salida de: para (var i en Datos) alerta (Datos [i]); y para (var i = 0; i <Data.length; i ++) alert (Data [i]);
Andrew D.
1

¿Por qué no usas una pequeña solución?

Cree una nueva matriz con nombres como índices. después de eso, todas las búsquedas usarán índices. Entonces, solo un bucle. ¡Después de eso no necesitas recorrer todos los elementos!

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

ejemplo en vivo


fuente
Eso significa recorrer todo primero ... luego modificar objetos (a menos que los clone pero eso es aún más sobrecargado). Y después de eso, vuelves a repetir (al menos parcialmente).
Jos
1

Respuesta extendida de Chris Pickett porque en mi caso necesitaba buscar más profundo que un nivel de atributo:

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

Puede pasar 'attr1.attr2' a la función

Ed Shee
fuente
1

¿Qué hay de esto? :

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

Suponiendo que esté usando lodash o underscorejs.

Ellone
fuente
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;
}

Si tiene un objeto con objetos múltiples, si desea saber si algún objeto está incluido en el objeto maestro, simplemente coloque find (MasterObject, 'Object to Search'), esta función devolverá la respuesta si existe o no (VERDADERO o FALSO ), Espero ayuda con esto, puede ver el ejemplo en JSFiddle .

Pedro Monteiro Arantes
fuente
Agregue alguna explicación con la respuesta sobre cómo esta respuesta ayuda a OP a solucionar el problema actual
ρяσѕρєя K
@ ρяσѕρєяK, gracias por su sugerencia, ya agregué la explicación :)
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;
});
Itay Merchav
fuente
1
collection.findIndex(item => item.value === 'smth') !== -1
Eugene Lyzo
fuente
Si bien este fragmento de código puede resolver la pregunta, incluir una explicación realmente ayuda a mejorar la calidad de su publicación. Recuerde que está respondiendo la pregunta para los lectores en el futuro, y que esas personas podrían no conocer los motivos de su sugerencia de código. ¡Intente también no saturar su código con comentarios explicativos, ya que esto reduce la legibilidad tanto del código como de las explicaciones!
Goodbye StackExchange el
1

Si desea obtener el valor del token de propiedad, también puede probar esto

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

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

donde _.findKey es una función de lodash

Akash Singh
fuente
0

Alternativamente a la respuesta de German Attanasio Ruiz, puede eliminar el segundo bucle utilizando Array.reduce () en lugar de Array.map ();

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

Usando guión bajo:

var index = _.indexOf(_.pluck(item , 'name'), 'Nick');
M Faisal Hameed
fuente