Найти индекс объекта в массиве с наивысшим значением свойства
У меня есть массив с объектами:
var articles = [];
var article = {};
Simple loop that iterates x times {
article.text = "foobar";
article.color = "red";
article.number = 5;
articles.push(article);
}
Я понятия не имею, сколько объектов будет в моем массиве, но все они будут иметь разные значения для своих свойств, я просто привел здесь несколько примеров.
Вопрос
Мне нужно найти способ пройти через все эти объекты и получить индекс объекта, который имеет наибольшее значение в article.number. Как я могу это достичь? Я могу использовать только javascript, jQuery и т.д. Никаких других языков.
Я предполагаю, что это будет связано с использованием $.grep и Math.max, но я застрял, я никогда раньше не работал с $.grep.
Короче:
var highestNumber = index of object where article.number is highest
Ответы
Ответ 1
Существует много способов сделать это: Math.max()
, $.grep
и $.map
- несколько, но простой и понятный метод, который должен быть понятным, - это просто перебрать объект и проверить, чем переменная, если она есть, установите для переменной большее число:
var highest = 0;
$.each(articles, function(key, article) {
if (article.number > highest) highest = article.number;
});
// highest now contains the highest number
Ответ 2
Underscore.js - замечательная библиотека, которая предоставляет функциональные операции для коллекций. Решение в подчеркивании:
var maxObj = _.max(array, function (obj) {
return obj.number;
});
var maxIndex = array.indexOf(maxObj);
В то время как этот пример довольно прост, масштабы операций красивы. Скажем, вы хотели бы суммировать свойство number для каждого объекта в массиве с текстом, равным Foo
, и цветом, равным red
:
var customSum = _.chain(array)
.where({
text: "Foo", color: "red"
})
.map(function(obj) {
return obj.number;
})
.reduce(function(memo, num) {
return memo + num;
}, 0)
.value();
Если вы вообще заинтересованы в производительности, внешняя библиотека, безусловно, путь. Существует огромное количество оптимизаций, которые могут предоставить внешние библиотеки, которые сложно сопоставить в вашем собственном коде. При этом, имея дело с небольшим количеством предметов (менее нескольких тысяч), не будет заметной разницы в производительности между любыми ответами, размещенными здесь. Не потейте бенчмаркинг и используйте ответ, наиболее понятный вам.
JSFiddle
Ответ 3
Как насчет:
articleWithMaxNumber = articles.slice(0).sort(
function(x, y) { return y.number - x.number })[0]
и если вам нужен индекс:
index = articles.indexOf(articleWithMaxNumber)
И для тех, кто считает, что сортировка может быть избыточной, чтобы получить максимальное значение:
articleWithMaxNumber = articles.reduce(function(max, x) {
return x.number > max.number ? x : max;
})
И вот общий подход, как найти максимум приложений-приложений с помощью map-reduce:
function maxBy(array, fn) {
return array.map(function(x) {
return [x, fn(x)]
}).reduce(function(max, x) {
return x[1] > max[1] ? x : max;
})[0]
}
articleWithMaxNumber = maxBy(articles, function(x) { return x.number })
Некоторые люди высказывали озабоченность по поводу того, что метод sort
является "медленным", по сравнению с итеративным. Здесь fiddle, который использует оба метода для обработки массива с 50000 элементами. Метод sort
"медленнее" примерно на 50 миллисекунд на моей машине. Зависит от приложения, но в большинстве случаев об этом не стоит говорить.
var articles = [];
var len = 50000;
while (len--) {
var article = {};
article.text = "foobar";
article.color = "red";
article.number = Math.random();
articles.push(article);
}
d = performance.now();
max1 = articles.slice(0).sort(
function(x, y) {
return y.number - x.number
})[0]
time1 = performance.now() - d
d = performance.now();
max2 = articles.reduce(function(max, x) {
return x.number > max.number ? x : max;
})
time2 = performance.now() - d
document.body.innerHTML = [time1, time2].join("<br>")
Ответ 4
Вот одно возможное решение
Javascript
var articles = [],
howMany = 5,
i = 0,
article,
highest;
while (i < howMany) {
article = {};
article.text = "foobar";
article.color = "red";
article.number = i;
articles.push(article);
i += 1;
}
console.log(articles);
hownMany = articles.length;
i = 0;
while (i < howMany) {
if (typeof highest !== "number" || articles[i].number > highest) {
highest = i;
}
i += 1;
}
console.log(articles[highest]);
Вкл jsfiddle
Вот тест производительности для текущих данных методов, не стесняйтесь добавлять ответы.
Ответ 5
Я не буду использовать ничего, как Math или jQuery, просто отсортируйте полученный массив и вытащите последний элемент:
var sortArticles = function (a, b)
{
return ( a.number - b.number ); // should have some type checks ? inverse order: swap a/b
}
articles.sort(sortArticles);
highestArticle = articles.pop(); // or articles[array.length-1];
// take care if srticles.length = null !
Пока у вас нет gazillions статей в вашей памяти, это самый быстрый способ.
Ответ 6
array[array.map((o)=>o.number).indexOf(Math.max(...array.map((o)=>o.number)))]
Средство получает элемент с индексом (i), где (i) - индекс наибольшего числа.
Ответ 7
items =>
items
.reduce(
( highest, item, index ) =>
item > highest.item
? { item, index }
: highest
, { item: Number.NEGATIVE_INFINITY }
)
.index