Метод indexOf в массиве объектов? - PullRequest
445 голосов
/ 29 декабря 2011

Какой лучший способ получить индекс массива, который содержит объекты?

Представьте себе этот сценарий:

var hello = {
    hello: 'world',
    foo: 'bar'
};
var qaz = {
    hello: 'stevie',
    foo: 'baz'
}

var myArray = [];
myArray.push(hello,qaz);

Теперь я хотел бы иметь indexOf объект, свойство hello которого равно 'stevie', которое в этом примере будет 1.

Я довольно новичок в JavaScript, и я не знаю, существует ли простой метод или мне нужно создать собственную функцию для этого.

Ответы [ 27 ]

916 голосов
/ 15 апреля 2013

Я думаю, что вы можете решить это в одной строке, используя map function:

pos = myArray.map(function(e) { return e.hello; }).indexOf('stevie');
321 голосов
/ 29 декабря 2011

Array.prototype.findIndex поддерживается во всех браузерах, кроме IE (без края).Но предоставленный polyfill хорош.

var indexOfStevie = myArray.findIndex(i => i.hello === "stevie");

Решение с картой в порядке.Но вы перебираете весь массив при каждом поиске.Это только наихудший случай для findIndex , который останавливает итерацию, как только найдено совпадение.

На самом деле нет краткого пути (когда разработчикам приходилось беспокоиться о IE8) , но вот общее решение:

var searchTerm = "stevie",
    index = -1;
for(var i = 0, len = myArray.length; i < len; i++) {
    if (myArray[i].hello === searchTerm) {
        index = i;
        break;
    }
}

или как функция:

function arrayObjectIndexOf(myArray, searchTerm, property) {
    for(var i = 0, len = myArray.length; i < len; i++) {
        if (myArray[i][property] === searchTerm) return i;
    }
    return -1;
}
arrayObjectIndexOf(arr, "stevie", "hello"); // 1

Только некоторые примечания:

  1. Не использовать for ... в циклах на массивах
  2. Обязательно вырваться из цикла или вернуться изФункция, как только вы нашли свою «иглу»
  3. Будьте осторожны с равенством объектов

Например,

var a = {obj: 0};
var b = [a];
b.indexOf({obj: 0}); // -1 not found
111 голосов
/ 22 июля 2016

В ES2015 это довольно просто:

myArray.map(x => x.hello).indexOf('stevie')

или, возможно, с лучшей производительностью для больших массивов:

myArray.findIndex(x => x.hello === 'stevie')
25 голосов
/ 29 декабря 2011
var idx = myArray.reduce( function( cur, val, index ){

    if( val.hello === "stevie" && cur === -1 ) {
        return index;
    }
    return cur;

}, -1 );
18 голосов
/ 03 июня 2013

Мне нравится ответ Пабло, но Array # indexOf и Array # map не работают во всех браузерах. Underscore будет использовать нативный код, если он доступен, но также имеет и запасные варианты. Кроме того, у него есть метод «отрывки» для того, чтобы делать в точности то, что делает метод анонимной карты Пабло.

var idx = _.chain(myArray).pluck("hello").indexOf("Stevie").value();
15 голосов
/ 28 марта 2013

Или прототип это:

Array.prototype.indexOfObject = function arrayObjectIndexOf(property, value) {
    for (var i = 0, len = this.length; i < len; i++) {
        if (this[i][property] === value) return i;
    }
    return -1;
}

myArr.indexOfObject("name", "stevie");
9 голосов
/ 09 ноября 2014

Краткое описание

myArray.indexOf('stevie','hello')

Варианты использования:

  /*****NORMAL****/  
[2,4,5].indexOf(4) ;//OUTPUT 1
 /****COMPLEX*****/
 [{slm:2},{slm:4},{slm:5}].indexOf(4,'slm');//OUTPUT 1
 //OR
 [{slm:2},{slm:4},{slm:5}].indexOf(4,function(e,i){
   return e.slm;
});//OUTPUT 1
/***MORE Complex**/
[{slm:{salat:2}},{slm:{salat:4}},{slm:{salat:5}}].indexOf(4,function(e,i){
   return e.slm.salat;
});//OUTPUT 1

API:

    Array.prototype.indexOfOld=Array.prototype.indexOf

    Array.prototype.indexOf=function(e,fn){
      if(!fn){return this.indexOfOld(e)}
      else{ 
       if(typeof fn ==='string'){var att=fn;fn=function(e){return e[att];}}
        return this.map(fn).indexOfOld(e);
      }
    };
6 голосов
/ 28 июня 2017

Я провел тестирование производительности различных ответов, которые каждый может запустить самостоятельно:

https://jsperf.com/find-index-of-object-in-array-by-contents

Исходя из моих начальных тестов в Chrome, следующий метод (с использованием цикла for, настроенного внутри прототипа) является самым быстрым:

Array.prototype.indexOfObject = function (property, value) {
    for (var i = 0, len = this.length; i < len; i++) {
        if (this[i][property] === value) return i;
    }
    return -1;
}

myArray.indexOfObject("hello", "stevie");

Этот код является слегка измененной версией ответа Натана Заетты.

В тестах производительности я попробовал это сделать с целью, находящейся в середине (индекс 500) и в самом конце (индекс 999) массива объектов 1000, и даже если я поставил цель как самый последний элемент в массив (это означает, что он должен пройти через каждый отдельный элемент в массиве, прежде чем он найден), он все равно оказывается самым быстрым.

Преимущество этого решения в том, что оно является одним из самых кратких для многократного выполнения, поскольку необходимо повторять только последнюю строку:

myArray.indexOfObject("hello", "stevie");
5 голосов
/ 02 апреля 2018

Хотя большинство других ответов здесь действительны. Иногда лучше сделать короткую простую функцию рядом с местом, где вы будете ее использовать.

// indexOf wrapper for the list of objects
function indexOfbyKey(obj_list, key, value) {
    for (index in obj_list) {
        if (obj_list[index][key] === value) return index;
    }
    return -1;
}
// Find the string in the list (default -1)
var test1 = indexOfbyKey(object_list, 'name', 'Stevie');
var test2 = indexOfbyKey(object_list, 'last_name', 'some other name');

Это зависит от того, что важно для вас. Это может сэкономить строки кода и быть очень умным, чтобы использовать однострочник, или поместить универсальное решение где-нибудь, которое охватывает различные крайние случаи. Но иногда лучше просто сказать: «вот так я это сделал», чем оставлять будущим разработчикам дополнительную работу по реинжинирингу. Особенно, если вы считаете себя «новичком», как в вашем вопросе.

5 голосов
/ 18 марта 2018

Я сравнил несколько методов и получил результат с самым быстрым способом решения этой проблемы. Это for петля. Это в 5+ раз быстрее, чем любой другой метод.

Вот страница теста: https://jsbench.me/9hjewv6a98

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...