2009-01-20 85 views
21

我有一個雙打數組,我想要最高值的索引。這些是我迄今爲止提出的解決方案,但我認爲必須有一個更優雅的解決方案。想法?如何使用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(); 
+1

我不知道人們是否真的在尋找這個問題時尋找這個問題? `System.Array.IndexOf(score,score.Max())`剛剛看到一個Unity開發人員使用下面的LINQ代碼來完成這個簡單的任務,並且我是面對面的。 – 2017-08-30 06:04:21

回答

39

我建議編寫自己的擴展方法(編輯是通用與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(); 

它是可怕的,我不建議你使用它 - 但它會工作。

+0

這不是LINQ Jon – 2009-01-20 19:40:09

+0

Linq是Objects,Pascal。 – Will 2009-01-20 19:43:31

+2

@Pascal:你如何定義LINQ?對我來說,關於LINQ的好處之一就是你可以添加自己的操作符,它們可以與預定義的符合。編輯性能問題。 – 2009-01-20 19:55:53

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

如果score不是一個數組,這將不會是一半壞...

3

我今天(得到的用戶陣列誰了最高年齡指數)有這個問題,我做了這樣:

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

這是在C#類,所以它的小白的解決方案,我'am肯定你的人更好:)

32

呃,爲什麼讓它過於複雜?這是最簡單的方法。

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

呀,你可以做一個擴展方法使用更少的內存,但除非你正在處理巨大的數組,你將永遠通知的區別。

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(); 
} 
0

如果你想要的東西,看起來LINQy,因爲這純粹是功能性的,那麼上面的喬恩長柄水杓的回答可以改寫爲:

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

這具有相同的計算複雜性,因爲對方的回答,但更多的是記憶,爲可枚舉的每個元素創建一箇中間答案。

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); 
相關問題