How can I get LINQ to return the index of the object which has the max value in a collection?

人盡茶涼 提交于 2019-12-07 07:39:18

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!