Вопрос по arrays, indexof, javascript – В массиве объектов самый быстрый способ найти индекс объекта, атрибуты которого соответствуют поисковому запросу.

118

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

<code>array[i].id = some number;
array[i].name = some name;
</code>

То, что я хочу сделать, это найти индексы объектов, где идентификатор равен, например, один из 0,1,2,3 или 4. Я полагаю, я мог бы просто сделать что-то вроде:

<code>var indexes = [];
for(i=0; i<array.length; i++) {
  (array[i].id === 0) ? { indexes[0] = i }
  (array[i].id === 1) ? { indexes[1] = i }
  (array[i].id === 2) ? { indexes[2] = i }
  (array[i].id === 3) ? { indexes[3] = i }
  (array[i].id === 4) ? { indexes[4] = i }
}
</code>

Хотя это будет работать, это выглядит довольно дорого и медленно (не говоря уже об уродливости), особенно если array.length может быть большим. Любые идеи о том, как украсить это немного? Я думал о том, чтобы как-то использовать array.indexOf, но не вижу, как форсировать синтаксис. это

<code>array.indexOf(this.id === 0);
</code>

например, возвращает undefined, как это должно быть. Заранее спасибо!

Я фанат синтаксиса ES6 (используйте полифилы, если требуется поддержка в старых браузерах). ES7 + ES8 будут в будущем Fr0zenFyr
Если у вас простой старый массив, все, что вы можете сделать, это итерировать. Это и есть массивы, набор объектов, упорядоченных по индексу массива. Dave Newton
Просто попробуйте этот пост сегодня, для всех опоздавших есть новый метод массиваArray.prototype.findIndex() в ECMAScript 2015. Принятый ответ был удивительным, хотя. Conrad Lo

Ваш Ответ

16   ответов
0

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

[{"a":true}, {"f":true}, {"g":false}]
.findIndex(function(element){return Object.keys(element)[0] == "g"});

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

45

Самый простой и легкий способ найти индекс элемента в массиве.

ES5 syntax: [{id:1},{id:2},{id:3},{id:4}].findIndex(function(obj){return obj.id == 3})

ES6 syntax: [{id:1},{id:2},{id:3},{id:4}].findIndex(obj => obj.id == 3)

Я считаю, что это самое элегантное решение. Для тех, кто беспокоится о обратной совместимости, вы можете найти полифилл дляfindIndex вdeveloper.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Я получаю предупреждение в своем инструменте ES6 Lint, чтоobj.id == 3 оператор, используемый здесь, может вызвать неожиданное преобразование типа, поэтому используйтеobj.id === 3 вместо этого оператор, который проверяет на одинаковое значение и тип.
2

Использование ES6map функция:

let idToFind = 3;
let index = someArray.map(obj => obj.id).indexOf(idToFind);
Это прекрасно работает для меня, спасибо!
26

Новый метод Array.фильтр() будет хорошо работать для этого:

var filteredArray = array.filter(function (element) { 
    return element.id === 0;
});

JQuery также может сделать это с.grep ()

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

Это не возвращает индекс.
+1, я всегда забываю о таких встроенных функциях на объектах.
Это не возвращает индекс.
Это не отвечает на этот конкретный вопрос, но мне очень помогает! Спасибо!
уценено, потому что это не возвращает индекс
3

Новый способ использования ES6

let picked_element = array.filter(element => element.id === 0);
0
var test = [
  {id:1, test: 1},
  {id:2, test: 2},
  {id:2, test: 2}
];

var result = test.findIndex(findIndex, '2');

console.log(result);

function findIndex(object) {
  return object.id == this;
}

вернет индекс 1 (работает только в ES 2016)

2

Похоже, вы могли бы создать простой итератор с обратным вызовом для тестирования. Вот так:

function findElements(array, predicate)
{
    var matchingIndices = [];

    for(var j = 0; j < array.length; j++)
    {
        if(predicate(array[j]))
           matchingIndices.push(j);
    }

    return matchingIndices;
}

Тогда вы можете вызвать так:

var someArray = [
     { id: 1, text: "Hello" },
     { id: 2, text: "World" },
     { id: 3, text: "Sup" },
     { id: 4, text: "Dawg" }
  ];

var matchingIndices = findElements(someArray, function(item)
   {
        return item.id % 2 == 0;
   });

// Should have an array of [1, 3] as the indexes that matched
358

Может быть, вы хотели бы использовать функции более высокого порядка, например & quot; map & quot ;. Предполагая, что вы хотите выполнить поиск по «полю»; атрибут:

var elementPos = array.map(function(x) {return x.id; }).indexOf(idYourAreLookingFor);
var objectFound = array[elementPos];
Что это возвращает, если оно не найдено? Я предполагаю -1, просто любопытно. Я поэкспериментирую.
@ NathanC.Tresch Возвращает -1, потому что этоindexOf возвращать значение, когда оно не может найти данное значение.
@ZeroAbsolute Ваша прикладная функция (переданная на карту) может вернуть хеш-строку, которая должна предоставить уникальный ключ для каждой возможной комбинации, заданной вашими критериями. Например:function hashf(el) { return String(el.id) + "_" + String(el.name); }, Это просто подсказка:elementPos = array.map(hashf(x)).indexOf(hash({id:3, name:'Pablo'})); Очевидно, что предоставленная мною хеш-функция подходит не для всех случаев, так как'_' может составлять часть ваших значений, но это лишь быстрый пример того, как вы можете найти различные методы хеширования.
Быстрый пример копирования-вставки для вас, чтобы поиграть с простым решением Pablo этой очень распространенной проблемы!var arrayOfObjects = [ { a: 1, aa: "two"}, // 0 { a: "asdf", aa: 2}, // 1 { a: "cat", aa: "dog"} // 2 ]; var elementPos = arrayOfObjects.map(function(x) {return x.aa; }).indexOf('dog'); var objectFound = arrayOfObjects[elementPos]; console.log(elementPos, objectFound); // 2 { a: 'cat', aa: 'dog' }
Этот ответ хорош, потому что он на самом деле отвечает на вопрос, предоставляя индекс :)
7
array.forEach(function (elem, i) {  // iterate over all elements of array
    indexes[elem.id] = i;           // take the found id as index for the
});                                 // indexes array and assign i

Результатом является список поиска для идентификатора. с заданным идентификатором мы получаем индекс записи.

2

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

  1. To return the index of the first occurrence.

const array = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 2 }];
const idYourAreLookingFor = 2;

//ES5 
//Output: 1
array.map(function (x) { return x.id; }).indexOf(idYourAreLookingFor);

//ES6 
//Output: 1
array.findIndex(obj => obj.id === idYourAreLookingFor);

  1. To return the index array of all occurrences, using reduce.

const array = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 2 }]
const idYourAreLookingFor = 2;

//ES5
//Output: [1, 4]
array.reduce(function (acc, obj, i) {
  if (obj.id === idYourAreLookingFor)
    acc.push(i);
  return acc;
}, []);

//ES6
//Output: [1, 4]
array.reduce((acc, obj, i) => (obj.id === idYourAreLookingFor) ? acc.concat(i) : acc, [])

0

Если вы заботитесь о производительности, не соглашайтесьfind или жеfilter или жеmap или любой из описанных выше способов

Вот пример, демонстрирующий самый быстрый метод.ВОТ это ссылка на реальный тест

Setup block

var items = []

for(var i = 0; i < 1000; i++) {
    items.push({id: i + 1})
}

var find = 523

Fastest Method

var index = -1
for(var i = 0; i < items.length; i++) {
    if(items[i].id === find) {
        index = i;
        break;
    }
}

Slower Methods

items.findIndex(item => item.id === find)

SLOWEST method

items.map(item => item.id).indexOf(find);
6
var indices = [];
var IDs = [0, 1, 2, 3, 4];

for(var i = 0, len = array.length; i < len; i++) {
    for(var j = 0; j < IDs.length; j++) {
        if(array[i].id == ID) indices.push(i);
    }
}
0

Я создал крошечную утилиту под названиемсупер-массив где вы можете получить доступ к элементам в массиве по уникальному идентификатору со сложностью O (1). Пример:

const SuperArray = require('super-array');

const myArray = new SuperArray([
  {id: 'ab1', name: 'John'},
  {id: 'ab2', name: 'Peter'},
]);

console.log(myArray.get('ab1')); // {id: 'ab1', name: 'John'}
console.log(myArray.get('ab2')); // {id: 'ab2', name: 'Peter'}
Вы можете прочитатьHow to offer personal open-source libraries? прежде чем опубликовать это везде.
@MartijnPieters Я разместил его только на несколько релевантных вопросов, и проект свободен от MIT, так что же это за сделка? Может быть, вы могли бы быть немного более терпимым.
5

Поскольку нет ответа с использованием обычного массиваfind:

var one = {id: 1, name: 'one'};
var two = {id: 2, name:'two'}
var arr = [one, two] 

var found = arr.find((a) => a.id === 2)

found === two // true

arr.indexOf(found) // 1
1

const index = array.findIndex(item => item.id === 'your-id');

Это должно получить индекс элемента в массиве с id === your-id

array = [ {id:1}, {id:2} ];

const index = array.findIndex(item => item.id === 2);

console.log(index);

2

Адаптация ответа Tejs для mongoDB и Robomongo I изменилась

matchingIndices.push(j);

в

matchingIndices.push(NumberInt(j+1));

Похожие вопросы