我有一个双打数组,我想要最高值的索引。这些是我到目前为止提出的解决方案,但我认为必须有一个更优雅的解决方案。想法?
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();
答案 0 :(得分:40)
我建议您编写自己的扩展方法(编辑为通用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。
关于特征的一句话:
至于这个“是否是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();
这很可怕,我建议你根本不使用它 - 但它会起作用。
答案 1 :(得分:36)
var indexAtMax = scores.ToList().IndexOf(scores.Max());
是的,您可以使用扩展方法来减少内存使用量,但除非您处理大型数组,否则永远不会注意到差异。
答案 2 :(得分:14)
var scoreList = score.ToList();
int topIndex =
(
from x
in score
orderby x
select scoreList.IndexOf(x)
).Last();
如果score
不是数组,那么这不会是一半......
答案 3 :(得分:4)
MoreLinq是一个提供此功能的库。等等。
答案 4 :(得分:2)
我今天遇到了这个问题(要获得年龄最大的用户数组中的索引),我就这样做了:
var position = users.TakeWhile(u => u.Age != users.Max(x=>x.Age)).Count();
这是在C#类,所以它的noob解决方案,我相信你的更好:)
答案 5 :(得分: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 );
答案 6 :(得分:1)
System.Linq.Enumerable.Select
(具有索引和System.Linq.Enumerable.Aggregate
)可以在一行中完成
public static int IndexOfMax<TSource>(this IEnumerable<TSource> source)
where TSource : IComparable<TSource> => source.Select((value, idx) => (value, idx))
.Aggregate((aggr, next) => next.value.CompareTo(aggr.value) > 0 ? next : aggr).idx;
答案 7 :(得分: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();
}
答案 8 :(得分:0)
如果你想要看起来像LINQy的东西,因为它纯粹是功能性的,那么Jon Skeets上面的回答可以改写为:
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;
}
这与其他答案具有相同的计算复杂度,但对内存更为夸大,为可枚举的每个元素创建一个中间答案。
答案 9 :(得分:0)
尝试使用完全是LINQ并具有最佳性能的一个:
var indexAtMax = scores.Select((x, i) => new { x, i })
.Aggregate((a, a1) => a.x > a1.x ? a : a1).i;