it-roy-ru.com

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

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

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
11
Rijstkoek

Есть много способов сделать это, 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
14
adeneo

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

11
ljfranklin

Как насчет:

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

5
georg

Вот одно из возможных решений

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

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

1
Xotic750
array[array.map((o)=>o.number).indexOf(Math.max(...array.map((o)=>o.number)))]

Означает получить элемент с индексом (i), где (i) - индекс наибольшего числа.

0
Abdennour TOUMI

Я не буду использовать что-либо вроде 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 !

Пока у вас в памяти нет миллиардов статей, это самый быстрый способ.

0
Axel Amthor
items => 
    items
        .reduce(
            ( highest, item, index ) => 
                item > highest.item 
                    ? { item, index }
                    : highest
        ,   { item: Number.NEGATIVE_INFINITY }
        )
        .index
0
kevin