C#如何查找数组中最大值及其索引

130

我有一个未排序的数字数组int[] anArray = { 1, 5, 2, 7 };,我需要获取数组中最大值的值和索引,这将是 7 和 3。如何实现这个功能?


到目前为止,我尝试使用Max()方法,然后使用二分查找方法来获取该最大值的索引,但是除非数组已排序,否则这种方法不起作用,所以我不能使用它。当我尝试时,它给了我负数。 - Edmund Rojas
@EdmundRojas 你不需要使用二分查找算法。对于未排序的列表,一个简单的线性查找就可以很好地解决问题。 - millimoose
22个回答

194

这可能不是最华丽的方式,但是能够起作用。

(必须要有 using System.Linq;)

 int maxValue = anArray.Max();
 int maxIndex = anArray.ToList().IndexOf(maxValue);

23
你可以节省很多编码时间,但最终需要对集合进行两次操作。 - Garo Yeriazarian
12
不需要.ToList(),数组已经显式实现了IList接口。 - millimoose
2
@millimoose,Array没有IndexOf方法,但你可以用Array.IndexOf(array,value)代替。这是List<T>的方法。 - sa_ddam213
1
@sa_ddam213 数组实现了 IList 接口,但是它们是显式实现的:http://msdn.microsoft.com/en-us/library/system.array.aspx#ExplicitInterfaceImplementationTableToggle。(数组还实现了相应的泛型 IList<T> 接口。) - millimoose
1
@sa_ddam213 不,ToList()的契约是始终进行复制。有时候进行复制,有时候不进行复制是一个可怕的想法 - 这将导致相当疯狂的别名错误。实际上,ToList()的实现或多或少是 return new List(source) - millimoose
显示剩余9条评论

52
int[] anArray = { 1, 5, 2, 7 };
// Finding max
int m = anArray.Max();

// Positioning max
int p = Array.IndexOf(anArray, m);

38
一个简洁的一句话:
var (number, index) = anArray.Select((n, i) => (n, i)).Max();

测试用例:

var anArray = new int[] { 1, 5, 7, 4, 2 };
var (number, index) = anArray.Select((n, i) => (n, i)).Max();
Console.WriteLine($"Maximum number = {number}, on index {index}.");
// Maximum number = 7, on index 2.

特点:

  • 使用 Linq(不如原生语言优化,但折衷方案是减少代码量)。
  • 无需排序。
  • 计算复杂度:O(n)。
  • 空间复杂度:O(n)。

备注:

  • 确保元组中的数字(而不是索引)是第一个元素,因为元组排序是从左到右比较元组项进行的。

2
这真的很棒!! - floydheld
2
应该指出的是,为了使其正常工作,被最大化的项目必须首先出现。 - Caius Jard
1
在元组中,例如 anArray.Select((n, i) => ( Index: i, Number: n)).Max() 找到的是最大索引而不是最大数字,因为元组的比较方式(item1 最重要等)的原因。 - Caius Jard
索引应该是3,而不是4。此外,在执行max函数时最好不要将最大值放在最高的索引处;这会隐藏错误的行为。相反,将其放在中间,或者在数组的开头、中间和结尾测试最大值。 - Tobias Knauss
好的,@TobiasKnauss,已经进行了更正,谢谢。 - Lesair Valmont
显示剩余3条评论

35

如果索引没有排序,则必须至少迭代一次数组才能找到最高值。我会使用简单的for循环:

int? maxVal = null; //nullable so this works even if you have all super-low negatives
int index = -1;
for (int i = 0; i < anArray.Length; i++)
{
  int thisNum = anArray[i];
  if (!maxVal.HasValue || thisNum > maxVal.Value)
  {
    maxVal = thisNum;
    index = i;
  }
}

这种方法比使用LINQ或其他一行代码的解决方案更冗长,但它可能会稍微快一点。实际上没有办法使其更快,它的时间复杂度是O(N)。


6
如果数组的长度至少为1,你可以通过将 maxVal 初始化为索引为0的数组值,将 index 初始化为0,并从 i=1 开始 for 循环来节省一次迭代。 - Jon Schneider

16

必做的 LINQ 一行代码[1]

var max = anArray.Select((value, index) => new {value, index})
                 .OrderByDescending(vi => vi.value)
                 .First();

(相比于其他解决方案,排序可能会影响性能。)

[1]: 对于给定的"one"值。


14
只是补充一下,这个解决方案的时间复杂度最好是O(nlogn)。对于未排序的数组,可以在O(n)的时间内找到最大值。 - dopplesoldner

3
这里有两种方法。您可能需要添加处理空数组的功能。
public static void FindMax()
{
    // Advantages: 
    // * Functional approach
    // * Compact code
    // Cons: 
    // * We are indexing into the array twice at each step
    // * The Range and IEnumerable add a bit of overhead
    // * Many people will find this code harder to understand

    int[] array = { 1, 5, 2, 7 };

    int maxIndex = Enumerable.Range(0, array.Length).Aggregate((max, i) => array[max] > array[i] ? max : i);
    int maxInt = array[maxIndex];

    Console.WriteLine($"Maximum int {maxInt} is found at index {maxIndex}");
}

public static void FindMax2()
{
    // Advantages: 
    // * Near-optimal performance

    int[] array = { 1, 5, 2, 7 };
    int maxIndex = -1;
    int maxInt = Int32.MinValue;

    // Modern C# compilers optimize the case where we put array.Length in the condition
    for (int i = 0; i < array.Length; i++)
    {
        int value = array[i];
        if (value > maxInt)
        {
            maxInt = value;
            maxIndex = i;
        }
    }

    Console.WriteLine($"Maximum int {maxInt} is found at index {maxIndex}");
}

2
 public static class ArrayExtensions
{
    public static int MaxIndexOf<T>(this T[] input)
    {
        var max = input.Max();
        int index = Array.IndexOf(input, max);
        return index;
    }
}

这适用于所有变量类型...

var array = new int[]{1, 2, 4, 10, 0, 2};
var index = array.MaxIndexOf();


var array = new double[]{1.0, 2.0, 4.0, 10.0, 0.0, 2.0};
var index = array.MaxIndexOf();

2

这个方法非常有效,不需要使用LINQ或其他扩展。

int[] anArray = { 1, 5, 2, 7 };
int i, mx;
int j = 0;

mx = anArray[0];


for (i = 1; i < anArray.Length; i++)
{
    if (anArray[i] > mx)
    {
        mx = anArray[i];
        j = i;
    }
}

Console.Write("The largest value is: {0}, of index: {1}", mx, j);

欢迎来到StackOverflow Robbie。虽然你的答案回答了问题,但是如果你能解释一下你代码中的操作,提供一个学习机会就更好了。 - Mike

2
int[] numbers = new int[7]{45,67,23,45,19,85,64}; 
int smallest = numbers[0]; 
for (int index = 0; index < numbers.Length; index++) 
{ 
 if (numbers[index] < smallest) smallest = numbers[index]; 
} 
Console.WriteLine(smallest);

1

以下是下面代码的输出:

00:00:00.3279270 - max1 00:00:00.2615935 - max2 00:00:00.6010360 - max3 (arr.Max())

虽然数组中有100000000个整数,但差别并不大...

class Program
    {
        static void Main(string[] args)
        {
            int[] arr = new int[100000000];

            Random randNum = new Random();
            for (int i = 0; i < arr.Length; i++)
            {
                arr[i] = randNum.Next(-100000000, 100000000);
            }
            Stopwatch stopwatch1 = new Stopwatch();
            Stopwatch stopwatch2 = new Stopwatch();
            Stopwatch stopwatch3 = new Stopwatch();
            stopwatch1.Start();

            var max = GetMaxFullIterate(arr);

            Debug.WriteLine( stopwatch1.Elapsed.ToString());


            stopwatch2.Start();
            var max2 = GetMaxPartialIterate(arr);

            Debug.WriteLine( stopwatch2.Elapsed.ToString());

            stopwatch3.Start();
            var max3 = arr.Max();
            Debug.WriteLine(stopwatch3.Elapsed.ToString());

        }



 private static int GetMaxPartialIterate(int[] arr)
        {
            var max = arr[0];
            var idx = 0;
            for (int i = arr.Length / 2; i < arr.Length; i++)
            {
                if (arr[i] > max)
                {
                    max = arr[i];
                }

                if (arr[idx] > max)
                {
                    max = arr[idx];
                }
                idx++;
            }
            return max;
        }


        private static int GetMaxFullIterate(int[] arr)
        {
            var max = arr[0];
            for (int i = 0; i < arr.Length; i++)
            {
                if (arr[i] > max)
                {
                    max = arr[i];
                }
            }
            return max;
        }

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