问题
I have a list of immutable objects (in my specific case a list of Tuple<double, double>) and I'd like to change the one with the highest Item2 value.
Ideally there would be an IndexOfMaxBy function I could use, so I could do:
var indexOfPointWithHighestItem2 = myList.IndexOfMaxBy(x => x.Item2);
var original = myList[indexOfPointWithHighestItem2];
myList[indexOfPointWithHighestItem2] =
new Tuple<double, double>(original.Item1, original.Item2 - 1);
I have seen How can I get LINQ to return the object which has the max value for a given property?, and using Jon Skeet's MaxBy function combined with Select I could do:
var indexOfPointWithHighestItem2 =
myList.Select((x, i) => new { Index = i, Value = x })
.MaxBy(x => x.Item2).Index;
But this creates a new object for every object in my list, and there must be a neater way. Does anyone have any good suggestions?
回答1:
Well, if you wanted to, you could of course write an IndexOfMaxByextension yourself.
Example(untested):
public static int IndexOfMaxBy<TSource, TProjected>
(this IEnumerable<TSource> source,
Func<TSource, TProjected> selector,
IComparer<TProjected> comparer = null
)
{
//null-checks here
using (var erator = source.GetEnumerator())
{
if (!erator.MoveNext())
throw new InvalidOperationException("Sequence is empty.");
if (comparer == null)
comparer = Comparer<TProjected>.Default;
int index = 0, maxIndex = 0;
var maxProjection = selector(erator.Current);
while (erator.MoveNext())
{
index++;
var projectedItem = selector(erator.Current);
if (comparer.Compare(projectedItem, maxProjection) > 0)
{
maxIndex = index;
maxProjection = projectedItem;
}
}
return maxIndex;
}
}
Usage:
var indexOfPointWithHighestItem2 = myList.IndexOfMaxBy(x => x.Item2);
回答2:
It looks like there is a FindIndex method defined on List that would be perfect for this:
double max = myList.Max(t => t.Item2);
int index = myList.FindIndex(t => t.Item2 == max);
来源:https://stackoverflow.com/questions/5189477/how-can-i-get-linq-to-return-the-index-of-the-object-which-has-the-max-value-in