Найти индекс объекта в массиве с наивысшим значением свойства

У меня есть массив с объектами:

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