如何使用LINQ获取数组中最高值的索引?

时间:2009-01-20 19:23:05

标签: c# linq

我有一个双打数组,我想要最高值的索引。这些是我到目前为止提出的解决方案,但我认为必须有一个更优雅的解决方案。想法?

double[] score = new double[] { 12.2, 13.3, 5, 17.2, 2.2, 4.5 };
int topScoreIndex = score.Select((item, indx) => new {Item = item, Index = indx}).OrderByDescending(x => x.Item).Select(x => x.Index).First();

topScoreIndex = score.Select((item, indx) => new {Item = item, Index = indx}).OrderBy(x => x.Item).Select(x => x.Index).Last();

double maxVal = score.Max();
topScoreIndex = score.Select((item, indx) => new {Item = item, Index = indx}).Where(x => x.Item == maxVal).Select(x => x.Index).Single();

10 个答案:

答案 0 :(得分:40)

我建议您编写自己的扩展方法(编辑为通用IComparable<T>约束。)

public static int MaxIndex<T>(this IEnumerable<T> sequence)
    where T : IComparable<T>
{
    int maxIndex = -1;
    T maxValue = default(T); // Immediately overwritten anyway

    int index = 0;
    foreach (T value in sequence)
    {
        if (value.CompareTo(maxValue) > 0 || maxIndex == -1)
        {
             maxIndex = index;
             maxValue = value;
        }
        index++;
    }
    return maxIndex;
}

请注意,如果序列为空,则返回-1。

关于特征的一句话:

  • 这适用于只能枚举一次的序列 - 这有时非常重要,通常是IMO的理想功能。
  • 内存复杂度为O(1)(与排序的O(n)相反)
  • 运行时复杂度为O(n)(与排序的O(n log n)相反)

至于这个“是否是LINQ”:如果它被列为标准LINQ查询运算符之一,你会把它算作LINQ吗?它是否感觉特别陌生或与其他LINQ运营商不同?如果MS将它作为​​新运算符包含在.NET 4.0中,那么它是LINQ吗?

编辑:如果你真的,真的非常喜欢使用LINQ(而不仅仅是获得一个优雅的解决方案),那么这里仍然是O(n)并且只评估序列一次:

int maxIndex = -1;
int index=0;
double maxValue = 0;

int urgh = sequence.Select(value => {
    if (maxIndex == -1 || value > maxValue)
    {
        maxIndex = index;
        maxValue = value;
    }
    index++;
    return maxIndex;
 }).Last();

这很可怕,我建议你根本不使用它 - 但它会起作用。

答案 1 :(得分:36)

嗯,为什么要让它过于复杂?这是最简单的方法。

var indexAtMax = scores.ToList().IndexOf(scores.Max());

是的,您可以使用扩展方法来减少内存使用量,但除非您处理大型数组,否则永远不会注意到差异。

答案 2 :(得分:14)

var scoreList = score.ToList();
int topIndex =
    (
      from x
      in score
      orderby x
      select scoreList.IndexOf(x)
    ).Last();

如果score不是数组,那么这不会是一半......

答案 3 :(得分:4)

MoreLinq是一个提供此功能的库。等等。

答案 4 :(得分:2)

我今天遇到了这个问题(要获得年龄最大的用户数组中的索引),我就这样做了:

var position = users.TakeWhile(u => u.Age != users.Max(x=>x.Age)).Count();

这是在C#类,所以它的noob解决方案,我相信你的更好:)

答案 5 :(得分:1)

这不是唯一基于聚合的解决方案,但这实际上只是一个单行解决方案。

double[] score = new double[] { 12.2, 13.3, 5, 17.2, 2.2, 4.5 };

var max = score.Select((val,ix)=>new{val,ix}).Aggregate(new{val=-1.0,ix=-1},(z,last)=>z.val>last.val?z:last);

Console.WriteLine ("maximum value is {0}", max.val );
Console.WriteLine ("index of maximum value is {0}", max.ix );

答案 6 :(得分:1)

System.Linq.Enumerable.Select(具有索引和System.Linq.Enumerable.Aggregate)可以在一行中完成

public static int IndexOfMax<TSource>(this IEnumerable<TSource> source)
    where TSource : IComparable<TSource> => source.Select((value, idx) => (value, idx))
    .Aggregate((aggr, next) => next.value.CompareTo(aggr.value) > 0 ? next : aggr).idx;

答案 7 :(得分:0)

最糟糕的复杂性是O(2N)〜= O(N),但需要对该集合进行两次枚举。

 void Main()
{
    IEnumerable<int> numbers = new int[] { 1, 2, 3, 4, 5 };

    int max = numbers.Max ();
    int index = -1;
    numbers.Any (number => { index++; return number == max;  });

    if(index != 4) {
        throw new Exception("The result should have been 4, but " + index + " was found.");
    }

    "Simple test successful.".Dump();
}

答案 8 :(得分:0)

如果你想要看起来像LINQy的东西,因为它纯粹是功能性的,那么Jon Skeets上面的回答可以改写为:

public static int MaxIndex<T>(this IEnumerable<T> sequence) where T : IComparable<T>
    {
        return sequence.Aggregate(
            new { maxIndex = -1, maxValue = default(T), thisIndex = 0 },
            ((agg, value) => (value.CompareTo(agg.maxValue) > 0 || agg.maxIndex == -1) ?
                             new {maxIndex = agg.thisIndex, maxValue = value, thisIndex = agg.thisIndex + 1} :
                             new {maxIndex = agg.maxIndex, maxValue = agg.maxValue, thisIndex = agg.thisIndex + 1 })).
            maxIndex;
    }

这与其他答案具有相同的计算复杂度,但对内存更为夸大,为可枚举的每个元素创建一个中间答案。

答案 9 :(得分:0)

尝试使用完全是LINQ并具有最佳性能的一个:

var indexAtMax = scores.Select((x, i) => new { x, i })
            .Aggregate((a, a1) => a.x > a1.x ? a : a1).i;