获取最大元素的索引
给出这样一个清单:
List intList = new List(); intList.Add(5); intList.Add(10); intList.Add(15); intList.Add(46);
你如何获得列表中最大元素的索引? 在这种情况下,它在索引3处。
编辑:标准LINQ不提供此function是一种遗憾。
这是一个简单*且相对有效的**解决方案:
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 :
!intList.Any() ? -1 :
如果列表为空,将强制-1
; -
Select
会将每个int
元素投影到一个具有两个属性的匿名类型:Value
和Index
; -
Aggregate
将获得具有最高Value
的元素; -
最后,我们得到所选元素的
Index
。
*简单是相对的。 这里的目的是达到可读性的平衡,并且仍然只扫描列表一次。
**在Select
期间分配大量新对象可能很浪费。 有些人测试过,它对大型列表表现不佳。
编辑1:添加空列表检查。
编辑2:增加了关于性能的警告。
这条路 :
var maxIndex = foo.IndexOf(foo.Max());
这是一个自定义LINQ方法,我相信你做的就是你想要的。 (我之前有另一个做投影的人,但你只需要调用Select即可,因为你只需要索引。)
public static int MaxIndex(this IEnumerable source) { IComparer comparer = Comparer .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; } }
以下是使用LINQ在一条(长)行中执行此操作的方法,只需一次通过集合即可。 它应该适用于任何IEnumerable
,而不仅仅是列表。
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 );
这是使用foreach
循环的上述非LINQ等价物。 (同样,只需要通过集合一次,并且应该适用于任何IEnumerable
。)
int maxIndex = -1, maxValue = int.MinValue, i = 0; foreach (int v in intList) { if ((maxIndex < 0) || (v > maxValue)) { maxValue = v; maxIndex = i; } i++; }
如果您知道该集合是IList
那么plain 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; } }
我无法改进Jon Skeet对一般案例的回答,因此我将在一份特定案例中获得“高绩效”奖。
public static class Extensions { public static int IndexOfMaximumElement(this IList 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方法:
private int ReturnMaxIdx(List 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; }
这至少是单次通过列表。
希望这可以帮助,
凯尔
使用自定义函数,使用Max()和IndexOf()花费更多。
这是我的解决方案:
public static int IndexOfMax(this IList 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(this IEnumerable TSource) { int i = -1; using (var iterator = TSource.GetEnumerator()) while (iterator.MoveNext()) i++; return i; } }
这是我解决这个问题的方法。 我返回-1而不是抛出exception,因为这是FindIndex函数的作用,我发现它非常方便。