C# 如何使用 LINQ 获取数组中最大值的索引?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/462699/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I get the index of the highest value in an array using LINQ?
提问by Guy
I have an array of doubles and I want the index of the highest value. These are the solutions that I've come up with so far but I think that there must be a more elegant solution. Ideas?
我有一个双打数组,我想要最高值的索引。这些是我迄今为止提出的解决方案,但我认为必须有一个更优雅的解决方案。想法?
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();
采纳答案by Jon Skeet
I suggest writing your own extension method (edited to be generic with an IComparable<T>
constraint.)
我建议编写您自己的扩展方法(编辑为具有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;
}
Note that this returns -1 if the sequence is empty.
请注意,如果序列为空,则返回 -1。
A word on the characteristics:
说一下特点:
- This works with a sequence which can only be enumerated once - this can sometimes be very important, and is generally a desirable feature IMO.
- The memory complexity is O(1) (as opposed to O(n) for sorting)
- The runtime complexity is O(n) (as opposed to O(n log n) for sorting)
- 这适用于只能枚举一次的序列 - 这有时非常重要,并且通常是 IMO 的理想功能。
- 内存复杂度为 O(1)(相对于排序的 O(n))
- 运行时复杂度为 O(n)(相对于排序的 O(n log n))
As for whether this "is LINQ" or not: if it had been included as one of the standard LINQ query operators, would you count it as LINQ? Does it feel particularly alien or unlike other LINQ operators? If MS were to include it in .NET 4.0 as a new operator, would it be LINQ?
至于这是否“是 LINQ”:如果它已作为标准 LINQ 查询运算符之一包含在内,您会将其视为 LINQ 吗?它是否感觉特别陌生或与其他 LINQ 运算符不同?如果 MS 将它作为新运算符包含在 .NET 4.0 中,它会是 LINQ 吗?
EDIT: If you're really, really hell-bent on using LINQ (rather than just getting an elegant solution) then here's one which is still O(n) and only evaluates the sequence once:
编辑:如果您真的非常非常喜欢使用 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();
It's hideous, and I don't suggest you use it at all - but it will work.
这太可怕了,我根本不建议您使用它 - 但它会起作用。
回答by Jon Skeet
var scoreList = score.ToList();
int topIndex =
(
from x
in score
orderby x
select scoreList.IndexOf(x)
).Last();
If score
wasn't an array this wouldn't be half bad...
如果score
不是一个数组,这不会是半坏...
回答by angularsen
回答by Vicente
I had this problem today (to get the index in a users array who had highest age), and I did on this way:
我今天遇到了这个问题(获取年龄最大的用户数组中的索引),我是这样做的:
var position = users.TakeWhile(u => u.Age != users.Max(x=>x.Age)).Count();
It was on C# class, so its noob solution, I′am sure your ones are better :)
它是在 C# 课上,所以它的菜鸟解决方案,我相信你的更好:)
回答by PJ7
Meh, why make it overcomplicated? This is the simplest way.
嗯,为什么要让它过于复杂?这是最简单的方法。
var indexAtMax = scores.ToList().IndexOf(scores.Max());
Yeah, you could make an extension method to use less memory, but unless you're dealing with huge arrays, you will nevernotice the difference.
是的,你可以做一个扩展方法来使用更少的内存,但除非你处理巨大的数组,否则你永远不会注意到差异。
回答by Marcel Valdez Orozco
The worst possible complexity of this is O(2N) ~= O(N), but it needs to enumerate the collection two times.
最糟糕的复杂度是 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();
}
回答by NickN
If you want something that looks LINQy, in that it's purely functional, then Jon Skeets' answer above can be recast as:
如果你想要一些看起来像 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;
}
This has the same computational complexity as the other answer, but is more profligate with memory, creating an intermediate answer for each element of the enumerable.
这与另一个答案具有相同的计算复杂性,但更浪费内存,为可枚举的每个元素创建一个中间答案。
回答by Cameron
This isn't the only Aggregate based solution, but this is really just a single line solution.
这不是唯一基于聚合的解决方案,但这实际上只是一个单行解决方案。
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 );
回答by Serge Sopotov
System.Linq.Enumerable.Select
with index and System.Linq.Enumerable.Aggregate
would do it in one line
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;
回答by Deepak Mishra
Try this one which is completely LINQ and has the best performance:
试试这个完全是 LINQ 并且性能最好的:
var indexAtMax = scores.Select((x, i) => new { x, i })
.Aggregate((a, a1) => a.x > a1.x ? a : a1).i;