C#查找最高的数组值和索引


89

所以我有一个未排序的数字数组int[] anArray = { 1, 5, 2, 7 };,我需要同时获取值和数组中最大值的索引(即7和3),我该怎么做?


到目前为止,香港专业教育学院试图使用Max()方法,然后使用二进制搜索方法来获取该最大值的索引,但是除非对数组进行了排序,否则我无法使用它,当我尝试将其赋予负数时,我无法使用它
Edmund Rojas

@EdmundRojas您不需要使用二进制搜索。一个普通的线性搜索对未排序的列表就很好了。
millimoose 2012年

Answers:


138

这不是最迷人的方法,但是有效。

(必须有using System.Linq;

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

10
您可以节省大量的编码时间,但是最终将需要遍历整个集合两次。
Garo Yeriazarian

11
您甚至不需要.ToList()显式实现的数组IList
millimoose12年

@GaroYeriazarian如果线性复杂度对于您的用例而言太大了,那么您可能需要削减更多的工作,而不仅仅是将常数因子减少三分之一。(尽管显然这不是微不足道的优化。)
millimoose 2012年

1
@ sa_ddam213数组实现了该IList接口,但它们明确地实现了该接口:msdn.microsoft.com/en-us/library/…。(数组还实现了相应的通用IList<T>接口。)
millimoose 2012年

1
@ sa_ddam213不,合同ToList()必须始终复制。有时会复制而不是有时不复制该方法将是一个可怕的想法–这将导致非常疯狂的别名错误。实际上,实现的ToList()程度或多或少return new List(source)
millimoose 2012年

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

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

28

如果索引未排序,则必须至少遍历一次数组以找到最大值。我会使用一个简单的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)更快的方法。


4
您可以通过初始化maxVal为索引0处的数组值(假设数组的长度至少为1),然后将其初始化index为0,然后在以下位置开始for循环来保存一次迭代i = 1
乔恩·施耐德

13

LINQ的强制性[1]-内衬:

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

(排序可能是对其他解决方案的性能影响。)

[1]:对于给定值“ 1”。


14
仅添加此解决方案最多就是O(nlogn)复杂性。对于未排序的数组,可以在O(n)时间内获得最大值。
dopplesoldner 2014年

13

简洁的单线:

var max = anArray.Select((n, i) => (Number: n, Index: i)).Max();

测试用例:

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

特征:

  • 使用Linq(没有像vanilla那样优化,但是折衷是更少的代码)。
  • 不需要排序。
  • 计算复杂度:O(n)。
  • 空间复杂度:O(n)。

备注:

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

这真的很整齐!
floydheld

应当指出的是,要使其正常运行,必须首先完成最大化的项目
Caius Jard

@CaiusJard是什么意思?如测试用例所示,正确找到了最大的项目这是最后一个项目。
Lesair Valmont

例如,首先在元组中anArray.Select((n, i) => ( Index: i, Number: n)).Max()找到元索引而不是最大数,这是因为元组的比较方式(item1最重要,等等)
Caius Jard

相当公平@CaiusJard,我加了点说明。谢谢。
Lesair Valmont

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

1
anArray.Select((n, i) => new { Value = n, Index = i })
    .Where(s => s.Value == anArray.Max());

这是一个O(n ^ 2)解决方案,因为您每次迭代都在计算anArray.Max()。对于大型阵列,这将变得非常缓慢。
尼尔

1
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-最大值1 00:00:00.2615935-最大值2 00:00:00.6010360-最大值3(arr.Max())

与数组中的1亿个整数相差不大,但仍然...

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;
        }

1
 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();

1
public static void Main()
{
    int a,b=0;
    int []arr={1, 2, 2, 3, 3, 4, 5, 6, 5, 7, 7, 7, 100, 8, 1};

    for(int i=arr.Length-1 ; i>-1 ; i--)
        {
            a = arr[i];

            if(a > b)
            {
                b=a;    
            }
        }
    Console.WriteLine(b);
}


0

这是LINQ解决方案,它是O(n)且具有适当的常数因子:

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

int index = 0;
int maxIndex = 0;

var max = anArray.Aggregate(
    (oldMax, element) => {
        ++index;
        if (element <= oldMax)
            return oldMax;
        maxIndex = index;
        return element;
    }
);

Console.WriteLine("max = {0}, maxIndex = {1}", max, maxIndex);

但是,for如果您关心性能,则应该写一个明确的小词。


0

只是使用的另一个角度DataTable。声明一个DataTable包含2个列的,分别为indexval。在该列中添加一个AutoIncrement选项以及AutoIncrementSeedAutoIncrementStep值。然后使用循环,将每个数组项作为行插入。然后通过使用1indexforeachdatatableSelect方法,选择具有最大值的行。

int[] anArray = { 1, 5, 2, 7 };
DataTable dt = new DataTable();
dt.Columns.AddRange(new DataColumn[2] { new DataColumn("index"), new DataColumn("val")});
dt.Columns["index"].AutoIncrement = true;
dt.Columns["index"].AutoIncrementSeed = 1;
dt.Columns["index"].AutoIncrementStep = 1;
foreach(int i in anArray)
    dt.Rows.Add(null, i);

DataRow[] dr = dt.Select("[val] = MAX([val])");
Console.WriteLine("Max Value = {0}, Index = {1}", dr[0][1], dr[0][0]);

输出量

Max Value = 7, Index = 4

在此处找到演示


0

查找数组中最大和最小的数字:

int[] arr = new int[] {35,28,20,89,63,45,12};
int big = 0;
int little = 0;

for (int i = 0; i < arr.Length; i++)
{
    Console.WriteLine(arr[i]);

    if (arr[i] > arr[0])
    {
        big = arr[i];
    }
    else
    {
        little = arr[i];

    }
}

Console.WriteLine("most big number inside of array is " + big);
Console.WriteLine("most little number inside of array is " + little);

1
它会返回大于/小于数组中第一个值的最后一个值,而不是最小/最大值。
Tomer Wolberg

0

如果您知道最大索引访问的最大值是立即的。因此,您所需的只是最大索引。

int max=0;

for(int i = 1; i < arr.Length; i++)
    if (arr[i] > arr[max]) max = i;

0

这是C#版本。它基于对数组进行排序的思想。

public int solution(int[] A)
 {
    // write your code in C# 6.0 with .NET 4.5 (Mono)
    Array.Sort(A);
    var max = A.Max();
    if(max < 0)
        return 1;
    else
        for (int i = 1; i < max; i++)
        {
            if(!A.Contains(i)) {
                return i;
            }
        }
    return max + 1;
}

0

考虑以下内容:

    /// <summary>
    /// Returns max value
    /// </summary>
    /// <param name="arr">array to search in</param>
    /// <param name="index">index of the max value</param>
    /// <returns>max value</returns>
    public static int MaxAt(int[] arr, out int index)
    {
        index = -1;
        int max = Int32.MinValue;

        for (int i = 0; i < arr.Length; i++)
        {
            if (arr[i] > max)
            { 
                max = arr[i];
                index = i;
            }
        }

        return max;
    }

用法:

int m, at;
m = MaxAt(new int[]{1,2,7,3,4,5,6}, out at);
Console.WriteLine("Max: {0}, found at: {1}", m, at);

0

for如果我们要打高尔夫球,可以通过无体循环来完成;)

//a is the array


int mi = a.Length - 1;
for (int i=-1; ++i<a.Length-1; mi=a[mi]<a[i]?i:mi) ;

的检查++i<a.Length-1遗漏检查的最后一个索引。如果我们将其设置为max索引是最后一个开始的索引,则我们不介意这一点。当循环为其他元素运行时,它将结束并且一个或另一个为真:

  • 我们找到了一个新的最大值,从而找到了一个新的最大指数 mi
  • 最后一个索引一直是最大值,所以我们没有找到新的索引,因此mi我们坚持使用初始mi

真正的工作是由循环后修饰符完成的:

  • 是最大值(a[mi]即数组索引为mi到目前为止找到)是否小于当前项?
    • 是的,然后mi记住i
    • 否,然后存储现有mi(无操作)

在操作结束时,您将找到要查找的最大值的索引。从逻辑上讲,最大值为a[mi]

考虑到如果您有一个数组,并且知道最大值的索引,最大值的实际值,我还不太明白“查找最大值和最大值的索引”是否也真正需要跟踪最大值使用索引对数组进行索引的情况很简单。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.