2009-07-16 110 views
18

的指數給出這樣一份清單:獲取最大元素

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

你如何獲得該產品的最大元素的索引?在這種情況下,它位於索引3處。

編輯:標準LINQ不提供此功能是很遺憾的。

回答

15

下面是一個簡單*和相對高效的解決方案**:

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. !intList.Any() ? -1 :將強制-1如果列表爲空;

  2. Select的將投射的每個int元件到一個匿名類型具有兩個屬性:ValueIndex;

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

  4. 最後,我們得到所選元素的Index

*簡單是相對的。這裏的目的是爲了達到可讀性的平衡,並且只能一次掃描列表。

**在Select期間分配大量新對象可能是浪費。正如有些人測試過的,對於大型列表來說效果不佳。

編輯1:添加空列表檢查。

編輯2:增加了關於性能的警告。

26

這樣:

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

這是乾淨而簡短的,但需要最多兩次完整的通過列表來獲取索引。如果你更快需要它,你應該使用for循環並隨時跟蹤索引。 – 2009-07-16 08:35:34

+5

它仍然是O(n),第二次傳球也許不是全傳。如果性能不是一個大問題,我會使用此代碼。 – 2009-07-16 12:11:15

+1

線上線從未失去魅力。 +1 – heltonbiker 2013-02-26 13:15:59

0

使用自定義功能,使用MAX()和的IndexOf()花費更多。

1

這裏的非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; 
     } 

這是一個單次通過列表中至少有。

希望這有助於

凱爾

11

這裏有一個自定義的LINQ方法,我相信你想要做什麼。 (我以前有另一個它做了預測,但你可以叫選擇這樣做,因爲你只需要索引。)

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

我不能喬恩斯基特的答案一般情況好轉,所以我將在特定的整數列表案例中爭取「高性能」獎。

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

以下是如何在一個使用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 
     ); 

這裏的非LINQ當量的上述的,使用foreach循環。 (同樣,只需一次通過收集,並應該爲任何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++; 
} 

如果您知道集合是一個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; 
    } 
} 
0

這裏是我的解決方案:

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

這是我在這個問題裂紋。我返回-1而不是拋出異常,因爲這是FindIndex函數的作用,我發現它非常方便。