Obtain the index of the maximum element

前端 未结 9 1527
梦谈多话
梦谈多话 2020-12-28 15:03

Given such a list:

        List intList = new List();
        intList.Add(5);
        intList.Add(10);
        intList.Add(15);
                


        
相关标签:
9条回答
  • 2020-12-28 15:33

    I can't improve on Jon Skeet's answer for the general case, so I am going for the 'high performance' prize in the specific case of a list of ints.

    public static class Extensions
    {
        public static int IndexOfMaximumElement(this IList<int> list)
        {
            int size = list.Count;
    
            if (size < 2)
                return size - 1;
    
            int maxValue = list[0];
            int maxIndex = 0;
    
            for (int i = 1; i < size; ++i)
            {
                int thisValue = list[i];
                if (thisValue > maxValue)
                {
                    maxValue = thisValue;
                    maxIndex = i;
                }
            }
    
            return maxIndex;
        }
    
    0 讨论(0)
  • 2020-12-28 15:36

    Here's how to do it in one (long) line using LINQ, with just a single pass through the collection. It should work for any IEnumerable<int>, not just lists.

    int maxIndex = intList
        .Select((x, i) => new { Value = x, Index = i })
        .Aggregate
            (
                new { Value = int.MinValue, Index = -1 },
                (a, x) => (a.Index < 0) || (x.Value > a.Value) ? x : a,
                a => a.Index
            );
    

    Here's the non-LINQ equivalent of the above, using a foreach loop. (Again, just a single pass through the collection, and should work for any IEnumerable<int>.)

    int maxIndex = -1, maxValue = int.MinValue, i = 0;
    foreach (int v in intList)
    {
        if ((maxIndex < 0) || (v > maxValue))
        {
            maxValue = v;
            maxIndex = i;
        }
        i++;
    }
    

    If you know that the collection is an IList<int> then a plain for loop is probably the easiest solution:

    int maxIndex = -1, maxValue = int.MinValue;
    for (int i = 0; i < intList.Count; i++)
    {
        if ((maxIndex < 0) || (intList[i] > maxValue))
        {
            maxValue = intList[i];
            maxIndex = i;
        }
    }
    
    0 讨论(0)
  • 2020-12-28 15:38

    Here is a simple* and relatively efficient** solution:

    int indexMax
        = !intList.Any() ? -1 :
        intList
        .Select( (value, index) => new { Value = value, Index = index } )
        .Aggregate( (a, b) => (a.Value > b.Value) ? a : b )
        .Index;
    
    1. The !intList.Any() ? -1 : will force a -1 if the list is empty;

    2. The Select will project each int element into an anonymous type with two properties: Value and Index;

    3. The Aggregate will get the element with the highest Value;

    4. Finally, we get the Index of the chosen element.

    * Simplicity is relative. The aim here was to reach a balance of readability and still only scan the list once.

    ** The allocation of lots of new objects during the Select is probably wasteful. As some people tested, it doesn't perform well for large lists.

    EDIT 1: empty list check added.

    EDIT 2: added caveats about performance.

    0 讨论(0)
  • 2020-12-28 15:40

    Here is my solution:

    public static int IndexOfMax(this IList<int> source)
    {
        if (source == null)
            throw new ArgumentNullException("source");
        if (source.Count == 0)
            throw new InvalidOperationException("List contains no elements");
    
        int maxValue = source[0];
        int maxIndex = 0;
        for (int i = 1; i < source.Count; i++)
        {
            int value = source[i];
            if (value > maxValue)
            {
                maxValue = value;
                maxIndex = i;
            }
        }
        return maxIndex;
    }
    
    0 讨论(0)
  • 2020-12-28 15:46

    this way :

    var maxIndex = foo.IndexOf(foo.Max());
    
    0 讨论(0)
  • 2020-12-28 15:46

    Here's the non-linq method if you like:

    private int ReturnMaxIdx(List<int> intList)
            {
                int MaxIDX = -1;
                int Max = -1;
    
                for (int i = 0; i < intList.Count; i++)
                {
                    if (i == 0)
                    {
                        Max = intList[0];
                        MaxIDX = 0;
                    }
                    else
                    {
                        if (intList[i] > Max)
                        {
                            Max = intList[i];
                            MaxIDX = i;
                        }
                    }
                }
    
                return MaxIDX;
            }
    

    This is a single pass through the list at least.

    Hope this helps,

    Kyle

    0 讨论(0)
提交回复
热议问题