如何让LINQ返回集合中具有最大值的对象的索引?

dom*_*nic 4 c# linq linq-to-objects

我有一个不可变对象列表(在我的特定情况下是一个列表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);
Run Code Online (Sandbox Code Playgroud)

我已经看到如何让LINQ返回具有给定属性的最大值的对象?,并使用Jon Skeet的MaxBy功能与Select我可以做到:

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

但是这会为我列表中的每个对象创建一个新对象,并且必须有一个更简洁的方法.有没有人有任何好的建议?

mel*_*okb 5

看起来有一个FindIndex定义的方法List对于这个是完美的:

double max = myList.Max(t => t.Item2);
int index = myList.FindIndex(t => t.Item2 == max);
Run Code Online (Sandbox Code Playgroud)

  • @dominic:根据所讨论列表的大小,它可能是值得的,只是为了避免编写样板代码.更少的错误来源和意图明确记录:)平均而言,无论如何,您不必经历两次列表.最坏的情况是最终值为最大值的排序列表. (2认同)

Ani*_*Ani 4

好吧,如果您愿意,您当然可以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;
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

var indexOfPointWithHighestItem2 = myList.IndexOfMaxBy(x => x.Item2);
Run Code Online (Sandbox Code Playgroud)

  • 为什么不使用“foreach”而不是“MoveNext”和“Current”? (2认同)