Ответ 1
Я думаю, вы можете решить его в одной строке, используя функцию карты:
pos = myArray.map(function(e) { return e.hello; }).indexOf('stevie');
Какой лучший способ получить индекс массива, который содержит объекты?
Представьте себе этот сценарий:
var hello = {
hello: 'world',
foo: 'bar'
};
var qaz = {
hello: 'stevie',
foo: 'baz'
}
var myArray = [];
myArray.push(hello,qaz);
Теперь я хотел бы иметь объект indexOf
, объект hello
'stevie'
, который в этом примере будет 1
.
Я новичок с JavaScript, и я не знаю, есть ли простой метод или я должен создать свою собственную функцию для этого.
Я думаю, вы можете решить его в одной строке, используя функцию карты:
pos = myArray.map(function(e) { return e.hello; }).indexOf('stevie');
Array.prototype.findIndex поддерживается во всех браузерах, отличных от IE (non-edge). Но polyfill предоставлен.
var indexOfStevie = myArray.findIndex(i => i.hello === "stevie");
Решение с картой в порядке. Но вы выполняете итерацию по всему массиву в каждом поиске. Это только худший случай для findIndex, который останавливает итерацию после нахождения совпадения.
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
В ES2015 это довольно просто:
myArray.map(x => x.hello).indexOf('stevie')
или, возможно, с лучшей производительностью для больших массивов:
myArray.findIndex(x => x.hello === 'stevie')
var idx = myArray.reduce( function( cur, val, index ){
if( val.hello === "stevie" && cur === -1 ) {
return index;
}
return cur;
}, -1 );
Мне нравится ответ Pablo, но массив Array # indexOf и Array # не работает во всех браузерах. Underscore будет использовать собственный код, если он доступен, но также имеет резервные копии. Кроме того, у него есть метод скручивания для того, чтобы делать то, что делает метод анонимной карты Pablo.
var idx = _.chain(myArray).pluck("hello").indexOf("Stevie").value();
Или прототип:
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");
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
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);
}
};
array.filter(function(item, indx, arr){ return(item.hello === 'stevie'); })[0];
Обратите внимание на [0]
.
Собственно использовать reduce
как в ответе Antonio Laguna
.
Извинения за краткость...
Я провел несколько тестов производительности различных ответов здесь, каждый из которых может запустить их самостоятельно:
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");
просто:
myArray.indexOf(myArray.filter(function(item) {
return item.hello == "stevie"
})[0])
Если вас интересует только поиск позиции, см. @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
Я сравнил несколько методов и получил результат с самым быстрым способом решения этой проблемы. Это цикл for
. Он 5+ раз быстрее, чем любой другой метод.
Вот тестовая страница: https://jsbench.me/9hjewv6a98
Смотрите этот пример: http://jsfiddle.net/89C54/
for (i = 0; i < myArray.length; i++) {
if (myArray[i].hello === 'stevie') {
alert('position: ' + i);
return;
}
}
Он начинает отсчитываться с нулем.
Я сделал общую функцию, чтобы проверить приведенный ниже код и работает для любого объекта
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 (означает соответствие найденному).
Используйте _.findIndex
из библиотека underscore.js
Здесь пример
_.findIndex([{a:1},{a: 2,c:10},{a: 3}], {a:2,c:10}) //1
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);
Попробуйте следующее:
console.log(Object.keys({foo:"_0_", bar:"_1_"}).indexOf("bar"));
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
Вы можете использовать собственную и удобную функцию 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);
Это способ найти индекс объекта в массиве
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;
}
}
Используя метод 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];
});
});
}
(из моего ответа на этот обман)
Если ваш объект является тем же объектом тех, которые вы используете в массиве, вы должны иметь возможность получить индекс объекта так же, как и вы, как если бы это была строка.
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
В то время как большинство других ответов здесь действительны. Иногда лучше всего просто сделать короткую простую функцию рядом с тем, где вы ее будете использовать.
// 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');
Это зависит от того, что важно для вас. Он может сэкономить строки кода и быть очень умным, чтобы использовать однострочный вкладыш, или разместить где-нибудь общее решение, которое охватывает различные граничные случаи. Но иногда лучше просто сказать: "Здесь я сделал это так", а не оставлять будущим разработчикам дополнительные обратные инженерные работы. Особенно, если вы считаете себя "новичком", как в своем вопросе.
Вы можете просто использовать
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);
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"));
Вы можете создать свой собственный прототип, чтобы сделать это:
что-то вроде:
Array.prototype.indexOfObject = function (object) {
for (var i = 0; i < this.length; i++) {
if (JSON.stringify(this[i]) === JSON.stringify(object))
return i;
}
}
Это работает без специального кода
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
Примечание: это не дает фактического индекса, он сообщает только, существует ли ваш объект в текущей структуре данных
Я предпочту использовать метод findIndex()
:
var index = myArray.findIndex('hello','stevie');
index
даст вам номер индекса.