C# 获取最大元素的索引

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1136174/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 09:05:04  来源:igfitidea点击:

Obtain the Index of the Maximum Element

c#linq

提问by Graviton

Given such a list:

鉴于这样的列表:

        List<int> intList = new List<int>();
        intList.Add(5);
        intList.Add(10);
        intList.Add(15);
        intList.Add(46);

how do you obtain the index of the maximum element in the list? In this case, it's at index 3.

你如何获得列表中最大元素的索引?在本例中,它位于索引 3。

Edit: It's a shame that standard LINQ doesn't ship this functionalities.

编辑:很遗憾标准 LINQ 没有提供此功能。

采纳答案by jpbochi

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 -1if the list is empty;

  2. The Selectwill project each intelement into an anonymous type with two properties: Valueand Index;

  3. The Aggregatewill get the element with the highest Value;

  4. Finally, we get the Indexof the chosen element.

  1. !intList.Any() ? -1 :将迫使-1如果列表是空的;

  2. Select将项目中的每个int元素为一个匿名类型具有两个属性:ValueIndex;

  3. Aggregate会得到最高的元素Value;

  4. 最后,我们得到Index所选元素的 。

* 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 Selectis probably wasteful. As some people tested, it doesn't perform well for large lists.

** 期间分配大量新对象Select可能是浪费。正如一些人测试的那样,它在大型列表中表现不佳。

EDIT 1:empty list check added.

编辑 1:添加了空列表检查。

EDIT 2:added caveats about performance.

编辑 2:添加了有关性能的警告。

回答by Sadegh

this way :

这边走 :

var maxIndex = foo.IndexOf(foo.Max());

回答by Clement Herreman

Use a custom function, using Max() and IndexOf() cost more.

使用自定义函数,使用 Max() 和 IndexOf() 成本更高。

回答by Kyle Rozendo

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

如果您愿意,这里是非 linq 方法:

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

凯尔

回答by Jon Skeet

Here's a custom LINQ method which I believe does what you want. (I previously had another which does a projection, but you can just call Select to do that, as you only need the index.)

这是一个自定义的 LINQ 方法,我相信它可以满足您的需求。(我以前有另一个进行投影,但您可以调用 Select 来执行此操作,因为您只需要索引。)

public static int MaxIndex<T>(this IEnumerable<T> source)
{
    IComparer<T> comparer = Comparer<T>.Default;
    using (var iterator = source.GetEnumerator())
    {
        if (!iterator.MoveNext())
        {
            throw new InvalidOperationException("Empty sequence");
        }
        int maxIndex = 0;
        T maxElement = iterator.Current;
        int index = 0;
        while (iterator.MoveNext())
        {
            index++;
            T element = iterator.Current;
            if (comparer.Compare(element, maxElement) > 0)
            {
                maxElement = element;
                maxIndex = index;
            }
        }
        return maxIndex;
    }
}

回答by Matt Howells

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.

我无法改进 Jon Skeet 对一般情况的回答,因此我将在整数列表的特定情况下获得“高性能”奖。

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

回答by LukeH

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.

以下是如何使用 LINQ 在一行(长)行中执行此操作,只需通过集合一次即可。它应该适用于任何IEnumerable<int>,而不仅仅是列表。

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 foreachloop. (Again, just a single pass through the collection, and should work for any IEnumerable<int>.)

这是使用foreach循环的上述非 LINQ 等效项。(同样,只需一次通过集合,应该适用于任何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 forloop is probably the easiest solution:

如果您知道集合是一个,IList<int>那么简单的for循环可能是最简单的解决方案:

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

回答by Alex

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

回答by Aelphaeis

public static class Extensions
{
    public static int MaxIndex<T>(this IEnumerable<T> TSource)
    {
        int i = -1;
        using (var iterator = TSource.GetEnumerator())
            while (iterator.MoveNext())
                i++;
        return i;
    }
}

Here is my crack at this problem. I returned -1 instead of throwing an exception because this is what the FindIndex function does and I find it very convenient.

这是我对这个问题的破解。我返回 -1 而不是抛出异常,因为这是 FindIndex 函数所做的,而且我发现它非常方便。