【问题标题】:Find index of object in array with highest value in property查找数组中具有最高属性值的对象的索引
【发布时间】:2013-05-06 17:18:10
【问题描述】:

我有一个包含对象的数组:

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

【问题讨论】:

  • 你不会写循环吗?访问属性?比较值并存储更高的值?你尝试过什么,你在哪里卡住了?
  • jQuery 不是一种语言!
  • 例如,如果您使用Underscore,则可以在一个语句中。 jQuery 库没有数据工具。
  • 您是特别想要索引,还是只想要包含该最大值的对象?后者更容易。
  • 你必须对值进行迭代才能找到最高的值,即使你使用一行 jQuery 进行迭代,迭代仍然在内部进行,所以它是一样的!

标签: javascript jquery arrays object


【解决方案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

【讨论】:

  • NB:$.each 看起来很慢。手动编写的 whilefor 循环将迭代得更快。
  • @Alnitak - 这只是为了简单起见,因为文章是一个对象数组,所以 for 循环也会更快,但 $.each 在大多数情况下都可以正常工作。
  • 我确实选择了for 循环,因为我不知道存在性能差异。还添加了一行来跟踪对象的索引,这是我的主要目标,但总的来说,这个答案对我帮助最大。
  • 将“最高”设置为键可能会更好,因为那将是 OP 所追求的索引。
【解决方案2】:

Underscore.js 是一个很棒的库,为集合提供功能操作。下划线的解决方案:

var maxObj = _.max(array, function (obj) {
  return obj.number;
});
var maxIndex = array.indexOf(maxObj);

虽然此示例相当简单,但操作的扩展性很好。假设您想对数组中文本等于 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

【讨论】:

  • underscore 是一个很棒的库,虽然我倾向于选择 lodash,因为它有更好的优化。但出于兴趣,我确实将它添加到了性能测试中:jsperf.com/fastest-highest 不过,如果你有能力,你还是无法击败自己。来自我的 +1
  • 如果你使用 Lodash,_.maxBy 是 ljfranklin 方法的简单替代品。 lodash.com/docs#maxBy
【解决方案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>")

【讨论】:

  • 是的。它表现不佳。虽然是一个简单的解决方案,但您至少应该指出它可能不是最好的。
  • @Bergi:真的吗?它从多少条目开始执行缓慢?与其他方法相比,它到底慢了多少?你有任何数据可以证明它“表现不佳”吗?
  • 排序最多是O(n log n),而搜索是O(n)。当然,会有一个交叉点,但是 Bergi 是对的,你永远不应该仅仅为了找到它的最大值而对数组进行排序。问题是,您事先不知道交叉点在哪里,但不接受基于排序的答案是不可行的。
  • @thg435 重点是,没有人知道,尽管这个数字应该“相对较低”。它依赖于实现和数据。对于小型数据集,时间差异无关紧要,因此请使用。对于大型数据集,差异非常重要,因此使用线性搜索。因此,如果数据集未知,请使用线性搜索。
  • 为了清晰起见,我喜欢通用方法,但值得注意的是,您需要一个现代浏览器,否则您将需要适当的 polyfill。此外,这些新方法往往很慢,因为它们没有“while”或“for”所具有的那种优化
【解决方案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

这是当前给定方法的performance test,请随时添加答案。

【讨论】:

  • 不要在数组上使用 for-in-loops,即使它使用 hasOwnProperty 保护!
  • Opps,我也不是这个意思,没有专注于我正在做的事情 :) 我正在考虑迭代对象
  • typeof 测试的意义何在?如果输入数据正确,则永远不会失败。
  • 尝试将未定义的数字与最高值进行比较。 jsfiddle.net/Xotic750/CZLPJ
  • 只是从highest = 0i = 1 开始?不重复这种情况会快得多……
【解决方案5】:
items => 
    items
        .reduce(
            ( highest, item, index ) => 
                item > highest.item 
                    ? { item, index }
                    : highest
        ,   { item: Number.NEGATIVE_INFINITY }
        )
        .index

【讨论】:

    【解决方案6】:

    我不会使用 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 !
    

    只要你的记忆中没有数以万计的文章,那是最快的方法。

    【讨论】:

    • @Xotic750:说真的,对于howMany = 5,任何测量都是有缺陷的。无论您选择哪种方法,计算都在亚微秒内完成。并为此答案 +1,因为它提到排序简单而简短,但如果您有大量文章,排序可能会太慢。
    • 我更要指出的是,如果您要声明某事是最快的,那么您应该准备好用可衡量的东西来支持该声明。顺便说一句,我没有投反对票。将其更改为 50000
    【解决方案7】:
    array[array.map((o)=>o.number).indexOf(Math.max(...array.map((o)=>o.number)))]
    

    表示获取索引为 (i) 的元素,其中 (i) 是最高数字的索引。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-07
      • 2021-12-06
      • 2022-01-07
      • 1970-01-01
      • 2014-11-22
      • 1970-01-01
      相关资源
      最近更新 更多