的指數給出這樣一份清單:獲取最大元素
List<int> intList = new List<int>();
intList.Add(5);
intList.Add(10);
intList.Add(15);
intList.Add(46);
你如何獲得該產品的最大元素的索引?在這種情況下,它位於索引3處。
編輯:標準LINQ不提供此功能是很遺憾的。
的指數給出這樣一份清單:獲取最大元素
List<int> intList = new List<int>();
intList.Add(5);
intList.Add(10);
intList.Add(15);
intList.Add(46);
你如何獲得該產品的最大元素的索引?在這種情況下,它位於索引3處。
編輯:標準LINQ不提供此功能是很遺憾的。
下面是一個簡單*和相對高效的解決方案**:
int indexMax
= !intList.Any() ? -1 :
intList
.Select((value, index) => new { Value = value, Index = index })
.Aggregate((a, b) => (a.Value > b.Value) ? a : b)
.Index;
該!intList.Any() ? -1 :
將強制-1
如果列表爲空;
Select
的將投射的每個int
元件到一個匿名類型具有兩個屬性:Value
和Index
;
該Aggregate
將得到最高的元素Value
;
最後,我們得到所選元素的Index
。
*簡單是相對的。這裏的目的是爲了達到可讀性的平衡,並且只能一次掃描列表。
**在Select
期間分配大量新對象可能是浪費。正如有些人測試過的,對於大型列表來說效果不佳。
編輯1:添加空列表檢查。
編輯2:增加了關於性能的警告。
這樣:
var maxIndex = foo.IndexOf(foo.Max());
使用自定義功能,使用MAX()和的IndexOf()花費更多。
這裏的非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;
}
這是一個單次通過列表中至少有。
希望這有助於
凱爾
這裏有一個自定義的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;
}
}
我不能喬恩斯基特的答案一般情況好轉,所以我將在特定的整數列表案例中爭取「高性能」獎。
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;
}
以下是如何在一個使用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;
}
}
這裏是我的解決方案:
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;
}
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函數的作用,我發現它非常方便。
這是乾淨而簡短的,但需要最多兩次完整的通過列表來獲取索引。如果你更快需要它,你應該使用for循環並隨時跟蹤索引。 – 2009-07-16 08:35:34
它仍然是O(n),第二次傳球也許不是全傳。如果性能不是一個大問題,我會使用此代碼。 – 2009-07-16 12:11:15
線上線從未失去魅力。 +1 – heltonbiker 2013-02-26 13:15:59