【问题标题】:C# find highest array value and indexC#查找最高数组值和索引
【发布时间】:2012-11-25 03:42:24
【问题描述】:

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

【问题讨论】:

  • 到目前为止,我尝试使用 Max() 方法,然后使用二进制搜索方法来获取该最大值的索引,但这不起作用,除非数组已排序,所以我不能使用它,当我试过它给了我负数
  • @EdmundRojas 你不需要使用二分搜索。普通的线性搜索对于未排序的列表非常有效。

标签: c# arrays indexing


【解决方案1】:

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

(必须有using System.Linq;

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

【讨论】:

  • 您节省了大量的编码时间,但最终您将遍历该集合两次。
  • 你甚至不需要.ToList(),数组显式实现IList
  • @millimoose,Array 没有 IndexOf 它是 List<T> 方法,但您可以用 Array.IndexOf(array,value) 代替
  • @sa_ddam213 数组实现了IList 接口,但它们明确地这样做了:msdn.microsoft.com/en-us/library/…。 (数组也实现了对应的泛型IList<T>接口。)
  • @sa_ddam213 不,ToList() 的合同是始终复制。让方法有时被复制有时不被复制是一个糟糕的主意——这会导致非常疯狂的别名错误。其实ToList()的实现或多或少是return new List(source)
【解决方案2】:
int[] anArray = { 1, 5, 2, 7 };
// Finding max
int m = anArray.Max();

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 您可以通过将 maxVal 初始化为索引 0 处的数组值(假设数组的长度至少为 1)、index 为 0 并在 @987654325 处开始 for 循环来节省一次迭代@.
    【解决方案4】:

    简洁的单行:

    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(不如 vanilla 优化,但代价是代码更少)。
    • 不需要排序。
    • 计算复杂度:O(n)。
    • 空间复杂度:O(n)。

    备注:

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

    【讨论】:

    • 这真是太棒了!!
    • 应该指出的是,要使其生效,被最大化的项目必须首先
    • @CaiusJard 是什么意思?如测试用例所示,最大项被正确找到并且它是最后一个。
    • 元组中的第一个,例如anArray.Select((n, i) =&gt; ( Index: i, Number: n)).Max() 查找最大索引而不是最大数量,因为比较元组的方式(item1 是最重要的等)
    • 很公平@CaiusJard,我添加了一条评论来指出这一点。谢谢。
    【解决方案5】:

    强制 LINQ one[1]-liner:

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

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

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

    【讨论】:

    • 仅添加此解决方案最多就是 O(nlogn) 复杂度。对于未排序的数组,可以在 O(n) 时间内找到最大值。
    【解决方案6】:

    这里有两种方法。当数组为空时,您可能需要添加处理。

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

    【讨论】:

      【解决方案7】:
       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();
      

      【讨论】:

        【解决方案8】:
        anArray.Select((n, i) => new { Value = n, Index = i })
            .Where(s => s.Value == anArray.Max());
        

        【讨论】:

        • 这是一个 O(n^2) 解决方案,因为您在每次迭代时都在计算 anArray.Max()。对于大型数组,这将变得非常缓慢。
        【解决方案9】:
        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);
        

        【讨论】:

          【解决方案10】:

          以下代码的输出:

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

          【讨论】:

            【解决方案11】:
            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);
            }
            

            【讨论】:

              【解决方案12】:
              int[] Data= { 1, 212, 333,2,12,3311,122,23 };
              int large = Data.Max();
              Console.WriteLine(large);
              

              【讨论】:

              • 您的答案只给出了最高值,但提问者要求最高值和最高值的索引。
              • 无法从数组中找到最大函数,除非您使用了“System.Linq”
              【解决方案13】:

              这是一个 O(n) 的 LINQ 解决方案,具有不错的常数因子:

              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 lop。

              【讨论】:

                【解决方案14】:

                使用DataTable 只是另一个视角。声明一个DataTable,其中包含两个名为indexval 的列。将AutoIncrement 选项以及AutoIncrementSeedAutoIncrementStep1 添加到index 列。然后使用foreach 循环并将每个数组项作为一行插入datatable。然后通过Select方法,选择具有最大值的行。

                代码

                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
                

                Find a demo here

                【讨论】:

                  【解决方案15】:

                  如果您知道访问最大值的最大索引是立即的。所以你只需要最大索引。

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

                  【讨论】:

                    【解决方案16】:

                    这是一个 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;
                    }
                    
                    

                    【讨论】:

                      【解决方案17】:

                      考虑以下:

                          /// <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);
                      

                      【讨论】:

                        【解决方案18】:

                        如果我们要去打高尔夫球,这可以通过一个无实体的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&lt;a.Length-1 的检查省略了检查最后一个索引。如果我们将其设置为好像最大索引是开始的最后一个索引,我们不介意这一点。当循环针对其他元素运行时,它将完成并且其中一个或另一个是正确的:

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

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

                        • 是目前我们找到的最大值(a[mi] 即由mi 索引的数组)小于当前项吗?
                          • 是的,然后通过记住i 来存储一个新的mi
                          • no 然后存储现有的mi (no-op)

                        在操作结束时,您将获得要找到最大值的索引。逻辑上那么最大值是a[mi]

                        如果你有一个数组,并且你知道最大值的索引,那么我不太明白“查找最大值和最大值的索引”是如何真正需要跟踪最大值的最大值是使用索引来索引数组的一个小例子。

                        【讨论】:

                          【解决方案19】:

                          这个长长的列表中的另一个答案,但我认为这是值得的,因为它提供了大多数(或所有?)其他答案没有的一些好处:

                          1. 以下方法仅在集合中循环一次,因此顺序为 O(N)
                          2. 该方法查找最大值的所有索引
                          3. 该方法可用于查找任何比较的索引minmaxequalsnot equals 等。
                          4. 该方法可以通过 LINQ 选择器查看对象

                          方法:

                          ///-------------------------------------------------------------------
                          /// <summary>
                          /// Get the indices of all values that meet the condition that is defined by the comparer.
                          /// </summary>
                          /// <typeparam name="TSource">The type of the values in the source collection.</typeparam>
                          /// <typeparam name="TCompare">The type of the values that are compared.</typeparam>
                          /// <param name="i_collection">The collection of values that is analysed.</param>
                          /// <param name="i_selector">The selector to retrieve the compare-values from the source-values.</param>
                          /// <param name="i_comparer">The comparer that is used to compare the values of the collection.</param>
                          /// <returns>The indices of all values that meet the condition that is defined by the comparer.</returns>
                          /// Create <see cref="IComparer{T}"/> from comparison function:
                          ///   Comparer{T}.Create ( comparison )
                          /// Comparison examples:
                          /// - max:      (a, b) => a.CompareTo (b)
                          /// - min:      (a, b) => -(a.CompareTo (b))
                          /// - == x:     (a, b) => a == 4 ? 0 : -1
                          /// - != x:     (a, b) => a != 4 ? 0 : -1
                          ///-------------------------------------------------------------------
                          public static IEnumerable<int> GetIndices<TSource, TCompare> (this IEnumerable<TSource> i_collection,
                                                                                             Func<TSource, TCompare> i_selector,
                                                                                             IComparer<TCompare> i_comparer)
                          {
                            if (i_collection == null)
                              throw new ArgumentNullException (nameof (i_collection));
                            if (!i_collection.Any ())
                              return new int[0];
                          
                            int index = 0;
                            var indices = new List<int> ();
                            TCompare reference = i_selector (i_collection.First ());
                          
                            foreach (var value in i_collection)
                            {
                              var compare = i_selector (value);
                              int result = i_comparer.Compare (compare, reference);
                              if (result > 0)
                              {
                                reference = compare;
                                indices.Clear ();
                                indices.Add (index);
                              }
                              else if (result == 0)
                                indices.Add (index);
                          
                              index++;
                            }
                          
                            return indices;
                          }
                          

                          如果不需要选择器,则将方法改为

                          public static IEnumerable<int> GetIndices<TCompare> (this IEnumerable<TCompare> i_collection,
                                                                                    IComparer<TCompare> i_comparer)
                          

                          并删除所有出现的i_selector

                          概念证明:

                          //########## test #1: int array ##########
                          int[] test = { 1, 5, 4, 9, 2, 7, 4, 6, 5, 9, 4 };
                          
                          // get indices of maximum:
                          var indices = test.GetIndices (t => t, Comparer<int>.Create ((a, b) => a.CompareTo (b)));
                          // indices: { 3, 9 }
                          
                          // get indices of all '4':
                          indices = test.GetIndices (t => t, Comparer<int>.Create ((a, b) => a == 4 ? 0 : -1));
                          // indices: { 2, 6, 10 }
                          
                          // get indices of all except '4':
                          indices = test.GetIndices (t => t, Comparer<int>.Create ((a, b) => a != 4 ? 0 : -1));
                          // indices: { 0, 1, 3, 4, 5, 7, 8, 9 }
                          
                          // get indices of all '15':
                          indices = test.GetIndices (t => t, Comparer<int>.Create ((a, b) => a == 15 ? 0 : -1));
                          // indices: { }
                          
                          //########## test #2: named tuple array ##########
                          var datas = new (object anything, double score)[]
                          {
                            (999,               0.1),
                            (new object (),     0.42),
                            ("hello",           0.3),
                            (new Exception (),  0.16),
                            ("abcde",           0.42)
                          };
                          // get indices of highest score:
                          indices = datas.GetIndices (data => data.score, Comparer<double>.Create ((a, b) => a.CompareTo (b)));
                          // indices: { 1, 4 }
                          

                          享受吧! :-)

                          【讨论】:

                            【解决方案20】:

                            找出数组中最大和最小的数:

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

                            【讨论】:

                            • 它将返回大于/小于数组中第一个值的最后一个值,而不是最小值/最大值。
                            猜你喜欢
                            • 2013-03-22
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 2017-08-13
                            • 1970-01-01
                            • 2013-05-06
                            相关资源
                            最近更新 更多