IndexOf в массиве объектов?

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

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

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

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

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

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

Ответ 1

Я думаю, вы можете решить его в одной строке, используя функцию карты:

pos = myArray.map(function(e) { return e.hello; }).indexOf('stevie');

Ответ 2

Array.prototype.findIndex поддерживается во всех браузерах, отличных от IE (non-edge). Но 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

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

  • Не использовать для... в циклах на массивах
  • Обязательно вырваться из цикла или вернуться из функции после того, как вы нашли свою "иглу"
  • Будьте осторожны с равенством объектов

Например,

var a = {obj: 0};
var b = [a];
b.indexOf({obj: 0}); // -1 not found

Ответ 3

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

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

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

myArray.findIndex(x => x.hello === 'stevie')

Ответ 4

var idx = myArray.reduce( function( cur, val, index ){

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

}, -1 );

Ответ 5

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

var idx = _.chain(myArray).pluck("hello").indexOf("Stevie").value();

Ответ 6

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

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");

Ответ 7

Краткая

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

Ответ 8

array.filter(function(item, indx, arr){ return(item.hello === 'stevie'); })[0];

Обратите внимание на [0].

Собственно использовать reduce как в ответе Antonio Laguna.

Извинения за краткость...

Ответ 9

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

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, и даже если я поставил цель в качестве последнего элемента в array (что означает, что он должен прокручивать каждый элемент в массиве до его обнаружения), он все равно заканчивается самым быстрым.

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

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

Ответ 10

просто:

myArray.indexOf(myArray.filter(function(item) {
    return item.hello == "stevie"
})[0])

Ответ 11

Если вас интересует только поиск позиции, см. @Pablo answer.

pos = myArray.map(function(e) { return e.hello; }).indexOf('stevie');

Однако, если вы хотите найти элемент (т.е. если вы подумывали сделать что-то вроде этого myArray[pos]), существует более эффективная однострочная strong > , чтобы сделать это, используя filter.

element = myArray.filter((e) => e.hello === 'stevie')[0];

См. результаты работы (~ + 42% оп/сек): http://jsbench.github.io/#7fa01f89a5dc5cc3bee79abfde80cdb3

Ответ 12

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

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

Ответ 13

Смотрите этот пример: http://jsfiddle.net/89C54/

for (i = 0; i < myArray.length; i++) {
    if (myArray[i].hello === 'stevie') {
        alert('position: ' + i);
        return;
    }
}

Он начинает отсчитываться с нулем.

Ответ 14

Я сделал общую функцию, чтобы проверить приведенный ниже код и работает для любого объекта

function indexOfExt(list, item) {
    var len = list.length;

    for (var i = 0; i < len; i++) {
        var keys = Object.keys(list[i]);
        var flg = true;
        for (var j = 0; j < keys.length; j++) {
            var value = list[i][keys[j]];
            if (item[keys[j]] !== value) {
                flg = false;
            }
        }
        if (flg == true) {
            return i;
        }
    }
    return -1;
}

var items = [{ "hello": 'world', "foo": 'bar' }];
var selectedItem = { "hello": 'world', "foo": 'bar' };
alert(items.indexOf(selectedItem));
alert(indexOfExt(items, selectedItem));

Первое предупреждение вернет -1 (означает совпадение не найдено), а второе предупреждение вернет 0 (означает соответствие найденному).

Ответ 15

Используйте _.findIndex из библиотека underscore.js

Здесь пример _.findIndex([{a:1},{a: 2,c:10},{a: 3}], {a:2,c:10}) //1

Ответ 16

Furthor @Monika Garg answer, вы можете использовать findIndex() (Существует polyfill для неподписанных браузеров).

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

Метод findIndex() возвращает индекс в массиве, если элемент в массиве удовлетворяет предоставленной функции тестирования. В противном случае возвращается -1.

Например:

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

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

var index = myArray.findIndex(function(element) {
  return element.hello == 'stevie';
});

alert(index);

Ответ 18

Вы можете использовать собственную и удобную функцию Array.prototype.findIndex() в основном:

Метод findIndex() возвращает индекс в массиве, если элемент в массиве удовлетворяет предоставленной функции тестирования. В противном случае возвращается -1.

Просто заметьте, что он не поддерживается в Internet Explorer, Opera и Safari, но вы можете использовать Polyfill, указанный в ссылке ниже.

Дополнительная информация:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex

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

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

var index = myArray.findIndex(function(element, index, array) {
  if (element.hello === 'stevie') {
    return true;
  }
});
alert('stevie is at index: ' + index);

Ответ 19

Это способ найти индекс объекта в массиве

    var myArray = [{  hello: 'world',
        foo: 'bar'
    },{
        hello: 'stevie',
        foo: 'baz'
    }];



    for (i = 0; i < myArray.length; i++) {
        if (myArray[i].hello === 'stevie') {
            alert('position: ' + i);
            return;
        }
    }

Ответ 20

Используя метод ES6 findIndex, без lodash или любых других библиотек, вы можете написать:

function deepIndexOf(arr, obj) {
  return arr.findIndex(function (cur) {
    return Object.keys(obj).every(function (key) {
      return obj[key] === cur[key];
    });
  });
}

Это будет сравнивать непосредственные свойства объекта, но не возвращаться в свойства.

Если ваша реализация еще не предоставляет findIndex (в большинстве случаев нет), вы можете добавить свет polyfill, который поддерживает этот поиск:

function deepIndexOf(arr, obj) {
  function findIndex = Array.prototype.findIndex || function (pred) {
    for (let i = 0; i < this.length; ++i) {
      if (pred.call(this, this[i], i)) {
        return i;
      }
    }

    return -1;
  }

  return findIndex.call(arr, function (cur) {
    return Object.keys(obj).every(function (key) {
      return obj[key] === cur[key];
    });
  });
}

(из моего ответа на этот обман)

Ответ 21

Если ваш объект является тем же объектом тех, которые вы используете в массиве, вы должны иметь возможность получить индекс объекта так же, как и вы, как если бы это была строка.

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

var qazCLONE = { // new object instance and same structure
    hello: 'stevie',
    foo: 'baz'
}

var myArray = [hello,qaz];

myArray.indexOf(qaz) // should return 1
myArray.indexOf(qazCLONE) // should return -1

Ответ 22

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

// 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');

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

Ответ 23

Вы можете просто использовать

const someId = 2;
const array = [{id:1}, {id:2}, {id:3}];
const index = array.reduce((i, item, index) => item.id === someId ? index : i, -1);
alert('someId ' + someId + ' is at index ' + index);

Ответ 24

var hello = {hello: "world",  foo: "bar"};
var qaz = {hello: "stevie", foo: "baz"};
var myArray = [];
myArray.push(hello,qaz);

function indexOfObject( arr, key, value   ) {
    var j = -1;
    var result = arr.some(function(obj, i) { 
        j++;
        return obj[key] == value;
    })

    if (!result) {
        return -1;
    } else {
        return j;
    };
}

alert(indexOfObject(myArray,"hello","world"));

Ответ 25

Вы можете создать свой собственный прототип, чтобы сделать это:

что-то вроде:

Array.prototype.indexOfObject = function (object) {
    for (var i = 0; i < this.length; i++) {
        if (JSON.stringify(this[i]) === JSON.stringify(object))
            return i;
    }
}

Ответ 26

Это работает без специального кода

var arr, a, found;
arr = [{x: 1, y: 2}];
a = {x: 1, y: 2};
found = JSON.stringify(arr).indexOf(JSON.stringify(a)) > - 1;
// found === true

Примечание: это не дает фактического индекса, он сообщает только, существует ли ваш объект в текущей структуре данных

Ответ 27

Я предпочту использовать метод findIndex():

 var index = myArray.findIndex('hello','stevie');

index даст вам номер индекса.