Как я могу заставить LINQ вернуть индекс объекта, который имеет максимальное значение в коллекции? - PullRequest
4 голосов
/ 04 марта 2011

У меня есть список неизменяемых объектов (в моем конкретном случае это список Tuple<double, double>), и я хотел бы изменить объект с наибольшим значением Item2.

В идеале должна быть функция IndexOfMaxByЯ мог бы использовать, поэтому я мог бы сделать:

var indexOfPointWithHighestItem2 = myList.IndexOfMaxBy(x => x.Item2);

var original = myList[indexOfPointWithHighestItem2];

myList[indexOfPointWithHighestItem2] = 
  new Tuple<double, double>(original.Item1, original.Item2 - 1);

Я видел Как я могу получить LINQ, чтобы вернуть объект, который имеет максимальное значение для данного свойства? , и используя Jon Skeet * Функция MaxBy в сочетании с Select I может сделать:

var indexOfPointWithHighestItem2 = 
  myList.Select((x, i) => new { Index = i, Value = x })
        .MaxBy(x => x.Item2).Index;

Но это создает новый объект для каждого объекта в моем списке, и должен быть более аккуратный способ.У кого-нибудь есть хорошие предложения?

Ответы [ 2 ]

5 голосов
/ 04 марта 2011

Похоже, существует метод FindIndex, определенный на List, который идеально подходит для этого:

double max = myList.Max(t => t.Item2);
int index = myList.FindIndex(t => t.Item2 == max);
4 голосов
/ 04 марта 2011

Ну, если вы хотите, вы, конечно, можете написать расширение IndexOfMaxBy самостоятельно.

Пример (не проверено):

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;
    }
}

Использование:

var indexOfPointWithHighestItem2 = myList.IndexOfMaxBy(x => x.Item2);
...