【问题标题】:Return index of greatest value in an array返回数组中最大值的索引
【发布时间】:2012-07-03 07:49:02
【问题描述】:

我有这个:

var arr = [0, 21, 22, 7];

将最大值的索引返回到另一个变量的最佳方法是什么?

【问题讨论】:

  • 只是对上面提供的答案的注释,LanilT 的答案是最快的!请参阅基准。常量 indexOfMaxValue = arr.indexOf(Math.max(...arr)); jsben.ch/6nmd2
  • @CyprianBergonia:为什么我的答案被排除在该基准之外?目前最快:jsben.ch/sxcMG(嗯,arr.indexOf(Math.max(...arr)) 也是我的答案,但功能之一。)

标签: javascript arrays max


【解决方案1】:

这可能是最好的方法,因为它可靠且适用于旧浏览器:

function indexOfMax(arr) {
    if (arr.length === 0) {
        return -1;
    }

    var max = arr[0];
    var maxIndex = 0;

    for (var i = 1; i < arr.length; i++) {
        if (arr[i] > max) {
            maxIndex = i;
            max = arr[i];
        }
    }

    return maxIndex;
}

还有这个单行:

let i = arr.indexOf(Math.max(...arr));

它会根据需要执行两倍的比较,但是会在大型数组上抛出RangeError。我会坚持这个功能。

【讨论】:

  • 好的,这个函数返回第一个遇到的索引以获得最大值。假设我有多个具有相同最高值的索引,我如何获得所有这些索引?
  • @ed1nh0:简单的方法是进行多次传递。用const max = arr.reduce((m, n) =&gt; Math.max(m, n))求最大值,则最大值的索引为[...arr.keys()].filter(i =&gt; arr[i] === max)
  • [...arr.keys()] 输出错误:unexpected token
  • 铬。我正在使用 VueJS,我想问题出在 webpack 配置上。
  • @ed1nh0:哪个版本的 Chrome?还是来自 webpack 构建的错误?
【解决方案2】:

除非我弄错了,否则我会说是编写自己的函数。

function findIndexOfGreatest(array) {
  var greatest;
  var indexOfGreatest;
  for (var i = 0; i < array.length; i++) {
    if (!greatest || array[i] > greatest) {
      greatest = array[i];
      indexOfGreatest = i;
    }
  }
  return indexOfGreatest;
}

【讨论】:

  • 不能很好地处理零作为最大值:findIndexOfGreatest( [-5, 0, -10, -1]) 返回 3...
【解决方案3】:

此函数的稳定版本如下所示:

// not defined for empty array
function max_index(elements) {
    var i = 1;
    var mi = 0;
    while (i < elements.length) {
        if (!(elements[i] < elements[mi]))
            mi = i;
        i += 1;
    }
    return mi;
}

【讨论】:

  • 在这种情况下“稳定”是什么意思?
  • 我猜他的意思是“合适的”
【解决方案4】:

一行并且可能比arr.indexOf(Math.max.apply(Math, arr))更快:

var a = [0, 21, 22, 7];
var indexOfMaxValue = a.reduce((iMax, x, i, arr) => x > arr[iMax] ? i : iMax, 0);

document.write("indexOfMaxValue = " + indexOfMaxValue); // prints "indexOfMaxValue = 2"

地点:

  • iMax - 迄今为止最好的索引(迄今为止最大元素的索引,在第一次迭代时iMax = 0 因为reduce() 的第二个参数是0,我们不能省略@987654328 的第二个参数@ 在我们的例子中)
  • x - 数组中当前测试的元素
  • i - 当前测试的索引
  • arr - 我们的数组 ([0, 21, 22, 7])

关于 reduce() 方法(来自 David Flanagan 的“JavaScript:权威指南”):

reduce() 有两个参数。第一个是执行归约操作的函数。此归约函数的任务是以某种方式将两个值组合或归约为一个值,并返回该归约值。

reduce() 使用的函数与 forEach() 和 map() 使用的函数不同。熟悉的值、索引和数组值作为第二个、第三个和第四个参数传递。第一个参数是到目前为止减少的累积结果。在第一次调用函数时,第一个参数是您传递的初始值 reduce() 的第二个参数。在后续调用中,它是上一次调用函数返回的值。

当你调用没有初始值的 reduce() 时,它使用数组的第一个元素作为初始值。这意味着对归约函数的第一次调用将具有第一个和第二个数组元素作为其 第一个和第二个参数。

【讨论】:

  • @traxium 虽然您的解释很好,但如果我们使用更多描述性变量,那么对于那些不太了解函数式编程的人来说,这个例子可能会更清楚。说:arr.reduce((bestIndexSoFar, currentlyTestedValue, currentlyTestedIndex, array) =&gt; currentlyTestedValue &gt; array[bestIndexSoFar] ? currentlyTestedIndex : bestIndexSoFar, 0);,可以描述为:从索引0开始迭代数组(第二个参数),如果currentlyTestedValue高于bestIndexSoFar处元素的值>,然后将 currentlyTestedIndex 作为 bestIndexSoFar 返回到下一次迭代。
  • @traxium 很棒的答案。我也同意@niieani 这是我实现的真实示例:this.methods.reduce((methodIndex, currentMethod, currentMethodIndex, methods) =&gt; currentMethod.price &lt;= methods[methodIndex].price ? currentMethodIndex : methodIndex, 0)
  • @DanielK,带有“完整”参数名称的答案不适合一个 stackoverflow 行。会出现一个水平滚动条,水平滚动时阅读sn-p不是很方便。无论如何感谢您的建议。我以另一种方式编辑了答案。
  • @traxium +1 获取 FP 解决方案。虽然对于刚开始使用 JS 的人来说它非常复杂,但您的解决方案也恰好是解决 OP 问题的最高效的解决方案之一。
  • 根据jsben.ch/ujXlk,另一种方法更快。
【解决方案5】:

编辑:多年前,我对此给出了一个粗略、过于具体和过于复杂的答案。所以我正在编辑它。我喜欢上面的功能性答案,因为它们的简洁因素而不是它们的可读性;但如果我更熟悉 javascript,那么我可能也会喜欢它们。

伪代码:

包含最大值的跟踪索引。假设索引 0 最初是最大的。与当前指数进行比较。如有必要,使用最大值更新索引。

代码:

var mountains = [3, 1, 5, 9, 4];

function largestIndex(array){
  var counter = 1;
  var max = 0;

  for(counter; counter < array.length; counter++){
    if(array[max] < array[counter]){
        max = counter;
    }
  }
  return max;
}

console.log("index with largest value is: " +largestIndex(mountains));
// index with largest value is: 3

【讨论】:

    【解决方案6】:

     var arr=[0,6,7,7,7];
     var largest=[0];
     //find the largest num;
     for(var i=0;i<arr.length;i++){
       var comp=(arr[i]-largest[0])>0;
          if(comp){
    	  largest =[];
    	  largest.push(arr[i]);
    	  }
     }
     alert(largest )//7
     
     //find the index of 'arr'
     var arrIndex=[];
     for(var i=0;i<arr.length;i++){
        var comp=arr[i]-largest[0]==0;
    	if(comp){
    	arrIndex.push(i);
    	}
     }
     alert(arrIndex);//[2,3,4]

    【讨论】:

      【解决方案7】:

      如果你使用下划线,你可以使用这个漂亮的短单线:

      _.indexOf(arr, _.max(arr))
      

      它将首先找到数组中最大项的值,在本例中为 22。然后它会返回 22 在数组中的索引,在本例中为 2。

      【讨论】:

        【解决方案8】:

        使用reduce 的另一种最大解决方案:

        [1,2,5,0,4].reduce((a,b,i) => a[0] < b ? [b,i] : a, [Number.MIN_VALUE,-1])
        //[5,2]
        

        如果数组为空,则返回 [5e-324, -1]。如果您只想要索引,请将[1] 放在后面。

        最小通过(更改为&gt;MAX_VALUE):

        [1,2,5,0,4].reduce((a,b,i) => a[0] > b ? [b,i] : a, [Number.MAX_VALUE,-1])
        //[0, 3]
        

        【讨论】:

        • 这不适用于所有负值的数组(总是返回 -1 作为索引)
        【解决方案9】:
        function findIndicesOf(haystack, needle)
        {
            var indices = [];
        
            var j = 0;
            for (var i = 0; i < haystack.length; ++i) {
                if (haystack[i] == needle)
                    indices[j++] = i;
            }
            return indices;
        }
        

        array 传递给haystackMath.max(...array) 传递给needle。这将给出数组的所有个最大元素,并且扩展性更强(例如,您还需要找到最小值)

        【讨论】:

          【解决方案10】:

          如果创建数组的副本并按降序排序,则副本的第一个元素将是最大的。比你可以在原始数组中找到它的索引。

          var sorted = [...arr].sort((a,b) => b - a)
          arr.indexOf(sorted[0])
          

          复制的时间复杂度为 O(n),排序的时间复杂度为 O(n*log(n)),indexOf 的时间复杂度为 O(n)。

          如果你需要做得更快,Ry 的答案是 O(n)。

          【讨论】:

            【解决方案11】:

            为了完成@VFDan 的工作,我对 3 种方法进行了基准测试:接受的方法(自定义循环)、reduce 和 find(max(arr)) 在 10000 个浮点数的数组上。

            在 chromimum 85 linux 上的结果(越高越好):

            • 自定义循环:100%
            • 减少:94.36%
            • indexOf(max): 70%

            firefox 80 linux 上的结果(越高越好):

            • 自定义循环:100%
            • 减少:96.39%
            • indexOf(max): 31.16%

            结论:

            如果您需要快速运行代码,请不要使用 indexOf(max)。 reduce 可以,但如果您需要最佳性能,请使用自定义循环。

            您可以使用此链接在其他浏览器上运行此基准测试: https://jsben.ch/wkd4c

            【讨论】:

              【解决方案12】:

              在考虑空数组的情况下,从@traxium 解决方案的“reduce”版本修改而来的小修改:

              function indexOfMaxElement(array) {
                  return array.reduce((iMax, x, i, arr) => 
                      arr[iMax] === undefined ? i :
                      x > arr[iMax]           ? i : iMax
                      , -1            // return -1 if empty
                  );
              }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2021-08-17
                • 2019-09-11
                • 1970-01-01
                • 1970-01-01
                • 2016-07-19
                • 1970-01-01
                • 2013-01-11
                相关资源
                最近更新 更多