代码之家  ›  专栏  ›  技术社区  ›  mafu

如何获取int数组中最小值的索引?

  •  17
  • mafu  · 技术社区  · 15 年前

    考虑到这是一个非常基本的任务,我想不出一个合适的简单方法来完成它。如何获取int数组中最小值的索引?可以使用linq/morelinq。到目前为止,我还找不到一艘合理的单程客轮。

    4 回复  |  直到 15 年前
        1
  •  20
  •   Ani    15 年前

    既然你提到Morelinq,那么:

    int[] array = ..
    
    // Will throw if the array is empty.
    // If there are duplicate minimum values, the one with the smaller
    // index will be chosen.
    int minIndex = array.AsSmartEnumerable()
                        .MinBy(entry => entry.Value)
                        .Index;
    

    另一种选择:

    // Will throw if the array is empty.
    // Requires two passes over the array. 
    int minIndex = Array.IndexOf(array, array.Min());
    

    当然,您可以编写自己的扩展方法:

    // Returns last index of the value that is the minimum.
    public static int IndexOfMin(this IEnumerable<int> source)
    {
       if(source == null)
         throw new ArgumentNullException("source");
    
       int minValue = int.MaxValue;
       int minIndex = -1;
       int index = -1;
    
       foreach(int num in source)
       {
          index++;
    
          if(num <= minValue)
          {
             minValue = num;
             minIndex = index;
          }
       }
    
       if(index == -1)
         throw new InvalidOperationException("Sequence was empty");
    
       return minIndex;
    }
    

    通过一些努力,您可以通过接受 IComparer<T> ,默认为 Comparer<T>.Default .

        2
  •  11
  •   shoelzer    11 年前

    对于这个问题,linq可能不是最好的解决方案,但这里还有另一个变体,即o(n)。它不排序,只遍历数组一次。

    var arr = new int[] { 3, 1, 0, 5 };
    int pos = Enumerable.Range(0, arr.Length)
        .Aggregate((a, b) => (arr[a] < arr[b]) ? a : b); // returns 2
    

    更新: 直接回答最初的问题,我会这样做:

    var arr = new int[] { 3, 1, 0, 5 };
    int pos = 0;
    for (int i = 0; i < arr.Length; i++)
    {
        if (arr[i] < arr[pos]) { pos = i; }
    }
    // pos == 2
    

    不,它不使用LINQ。是的,不止一行。但它真的很简单也很快。把它变成一个很小的方法,在一条线上的任何地方调用它: pos = FindMinIndex(arr);

        3
  •  5
  •   Alex Humphrey    15 年前

    对记忆不太友好,但是…

    array.Select((n, i) => new { index = i, value = n })
         .OrderBy(item => item.value)
         .First().index
    
        4
  •  2
  •   LukeH    15 年前

    它很难看,但它只需要一次序列传递,并且只使用内置框架方法:

    int index = yourArray.Select((x, i) => new { Val = x, Idx = i })
                         .Aggregate(new { Val = -1, Idx = -1 },
                                    (a, x) => (x.Idx == 0 || x.Val < a.Val) ? x : a,
                                    x => x.Idx);
    

    当然,您还可以编写一个通用扩展方法:

    int index = yourArray.MinIndex();
    
    // ...
    
    public static class EnumerableExtensions
    {
        public static int MinIndex<T>(
            this IEnumerable<T> source, IComparer<T> comparer = null)
        {
            if (source == null)
                throw new ArgumentNullException("source");
    
            if (comparer == null)
                comparer = Comparer<T>.Default;
    
            using (var enumerator = source.GetEnumerator())
            {
                if (!enumerator.MoveNext())
                    return -1;    // or maybe throw InvalidOperationException
    
                int minIndex = 0;
                T minValue = enumerator.Current;
    
                int index = 0;
                while (enumerator.MoveNext())
                {
                    index++;
                    if (comparer.Compare(enumerator.Current, minValue) < 0)
                    {
                        minIndex = index;
                        minValue = enumerator.Current;
                    }
                }
                return minIndex;
            }
        }
    }