How would you get the index of the lowest value in an int array?

前端 未结 5 1778
旧巷少年郎
旧巷少年郎 2020-12-28 16:45

Considering that this is a very basic task, I could not think of an appropriately easy way to do it. How would you get the index of the lowest value in an int array? Using L

相关标签:
5条回答
  • 2020-12-28 17:21
    int[] data = new []{ 10, 2, 3, 4, 2 };
    var index = data
      .Select((v, i) =>new {Index = i, Val = v})
      .FirstOrDefault(v => v.Val == data.Min()).Index; // 1
    

    But be careful, because you remember that you will get an exception if the array is null

    0 讨论(0)
  • 2020-12-28 17:23

    LINQ probably isn't the best solution for this problem, but here's another variation that is O(n). It doesn't sort and only traverses the array once.

    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
    

    Update: Answering the original question directly, this is how I would do it:

    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
    

    No, it doesn't use LINQ. Yes, it is more than one line. But it is really simple and really fast. Make it into a tiny little method and call it from anywhere on a single line: pos = FindMinIndex(arr);

    0 讨论(0)
  • 2020-12-28 17:23

    It's ugly but it only needs a single pass through the sequence and only uses built-in framework methods:

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

    And, of course, you can write a general-purpose extension method:

    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;
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-28 17:40

    Since you mention MoreLinq, how about:

    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;
    

    Another alternative:

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

    You could of course write your own extension-method:

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

    With some effort, you can generalize this to any type by accepting an IComparer<T>, defaulting to Comparer<T>.Default.

    0 讨论(0)
  • 2020-12-28 17:45

    Not very memory friendly, but...

    array.Select((n, i) => new { index = i, value = n })
         .OrderBy(item => item.value)
         .First().index
    
    0 讨论(0)
提交回复
热议问题