在数组中找到第二大的数

8

我有一个包含三个元素的数组,如[31,23,12],我想找到第二大的元素及其相关位置,而不重新排列数组

示例:

array = [21,23,34]

第二大的数为23;

它的位置是第1个。


我已经尝试对数组进行排序,但在排序后,我无法找到先前数组元素的索引。 - sachin yadav
你是不是想说第二大的元素? - Alexandre Alencar
是的,但当我对数组进行排序时,函数中存在的所有数组都会发生变化。 - sachin yadav
可能是如何在JavaScript中从数组中获取第二大的元素的重复问题。 - Kirill Simonov
1
请点击以下链接查看: https://dev59.com/Mafja4cB1Zd3GeqPuFWY#57360512 - Chang
显示剩余8条评论
29个回答

6

使用 .slice(0) 创建原始数组的克隆,例如:

var temp_arr = arr.slice(0);

将数组排序,以便您在索引temp_arr.length - 2处获得第二大的值:

temp_arr.sort()[temp_arr.length - 2]

现在,您可以使用indexOf()函数来获取检索到的值的索引,例如:
arr.indexOf(second_largest_value);

var arr = [23, 21, 34, 34];
var temp_arr = [...new Set(arr)].slice(0); //clone array
var second_largest_value = temp_arr.sort()[temp_arr.length - 2];
var index_of_largest_value = arr.indexOf(second_largest_value);

console.log(second_largest_value);
console.log(index_of_largest_value);


如果arr数组有两个最高的数字,例如34、34,则无法找到第二大的数字。 - artworkjpm

4

我在这里尽可能地简化了答案,你可以把它看作非常简单

function getSecondLargest(nums) {
    var flarge = 0;
    var slarge = 0;
    for (var i = 0; i < nums.length; i++) { 
            if (flarge < nums[i]) {
                slarge = flarge;
                flarge = nums[i];
            } else if (nums[i] > slarge) { 
                slarge = nums[i]

            }
        }
        return slarge; 
}

这是完全逻辑化的,这里没有数组排序或反转,当在数组中存在重复值时,你也可以使用这个方法


4

使用 ES6 SetArray.from

const secondLargest = (arr) => Array.from([...new Set(arr)]).sort((a,b) => b-a)[1]

上述函数使用 Set 删除重复元素,并返回排序后数组中的第二大元素。


3
function getSecondLargest(nums) {
nums.sort(function(x,y){
       return y-x;
    });
for(var j=1; j < nums.length; j++)
 {
    if(nums[j-1] !== nums[j])
    {
         return nums[j];
    }
 }
}
getSecondLargest([1,2,3,4,5,5]);

输出:4

这种方法还可以处理数组中一个数字的多次出现。在这里,我们首先对数组进行排序,然后忽略相同的数字并返回答案。


2

找到n个最大数的简单递归函数,而不需要重新排列数组:

编辑: 也适用于有多个相等的最大数的情况。

Original Answer: 最初的回答

let array = [11,23,34];

let secondlargest = Max(array, 2);
let index = array.indexOf(secondlargest);

console.log("Number:", secondlargest ,"at position", index);

function Max(arr, nth = 1, max = Infinity) {
  let large = -Infinity;
  for(e of arr) {
    if(e > large && e < max ) {
      large = e;
    } else if (max == large) {
      nth++;
    }
  }
  if(nth==0) return max;
  return Max(arr, nth-1, large);
}


2

var arr = [21,23,34];
var output = getSecondLargest(arr);

document.getElementById("output").innerHTML = output;

function getSecondLargest(nums) {
    if (nums.length == 0){
         return undefined;
    }
    nums.sort((a,b) => b-a);
    var newArr = [...new Set(nums)];
    return newArr[1];
}
<p id="output"></p>


2

function getSecondLargest(nums) {
  const sortedArray = new Set(nums.sort((a, b) => b - a)).values();
  sortedArray.next();

  return sortedArray.next().value;
}

console.log(getSecondLargest([1, 2, 4, 4, 3]));


2

这段代码将会返回第二大的数及其索引

const a = [1, 2, 3, 4, 6, 7, 7, 8, 15]

a.sort((a,b)=>a-b) //sorted small to large
const max = Math.max(...a)
const index = a.indexOf(max)
const s = {secondLargest:a[index-1],index:index-1}
console.log(s)


你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心找到有关如何编写良好答案的更多信息。 - Community

2
您可以使用 spreadsort() 创建原始 array 的副本。然后,只需从数组中获取倒数第二个数字,并使用 indexOf 揭示其索引。

const array = [21,23,34];
const arrayCopy = [...array];

const secondLargestNum = arrayCopy.sort()[arrayCopy.length - 2]

console.log(array.indexOf(secondLargestNum));

如果兼容性是问题,您可以使用concat复制数组:

var array = [21, 23, 34];
var arrayCopy = [].concat(array);

var secondLargestNum = arrayCopy.sort()[arrayCopy.length - 2]

console.log(array.indexOf(secondLargestNum));


1
从评论来看,楼主不想改变原始的数组。我已经更新了我的答案以反映这一点。 - Carl Edwards
看起来IE不支持原生的(震惊),但是在我的更新答案中仍然支持替代方案。 - Carl Edwards

2

这种方法最为冗长,但也是算法效率最高的。它只需要对原始数组进行一次遍历,不需要复制数组,也不需要排序。它还符合ES5标准,因为你问到了支持性。

var array = [21,23,34];

var res = array.reduce(function (results, curr, index) {
    if (index === 0) {
        results.largest = curr;
        results.secondLargest = curr;
        results.indexOfSecondLargest = 0;
        results.indexOfLargest = 0;
    }
    else if (curr > results.secondLargest && curr <= results.largest) {
        results.secondLargest = curr;
        results.indexOfSecondLargest = index;
    }
    else if (curr > results.largest) {
        results.secondLargest = results.largest;
        results.largest = curr;
        results.indexOfSecondLargest = results.indexOfLargest;
        results.indexOfLargest = index;
    }
    return results;
}, {largest: -Infinity, secondLargest: -Infinity, indexOfLargest: -1, indexOfSecondLargest: -1});

console.log("Second Largest: ", res.secondLargest);
console.log("Index of Second Largest: ", res.indexOfSecondLargest);


@sachinyadav “这种方式最冗长, 但也是最高效的算法” 我帖子里的第一句话哈哈 - mhodges
@sachinyadav 该解决方案会对数组进行3次迭代(slicesortindexOf),并且不会同时返回数字和相应的索引。 - mhodges
你能简要描述一下 reduce 的第二个参数(值为 -Infinity 的对象)是做什么的吗? - Dan Zuzevich
@DanielZuzevich 它是作为 reduce 回调函数的第一个参数传递的初始值。您可以传递任何您想要的初始值,因为它仅与第一次迭代有关。每个后续迭代使用回调函数的返回值作为上一次迭代的“结果”参数。我希望这讲得通,有点难以解释。 - mhodges

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接