如何使用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(); 

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

 public static int MaxIndex(this IEnumerable sequence) where T : IComparable { 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(); 

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

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

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

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

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

如果score不是数组,这不会是一半坏…

MoreLinq是一个提供此function的库。

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

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

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

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

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

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

  void Main() { IEnumerable 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(); } 

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

 public static int MaxIndex(this IEnumerable sequence) where T : IComparable { 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; } 

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