从C#中的List检索max元素索引的优雅方法

时间:2012-05-24 07:43:51

标签: c# collections

我发现了C#提供的工具来处理集合。

假设我有元素列表,我想检索最满足属性的那个。基本上是elements.Max(predicate),除了我对最佳元素的索引感兴趣。我想要索引而不是元素本身的原因可能是没有这样的元素,并且类型是不可为空的。

编写执行此操作的函数是微不足道的,但我感兴趣的是使用C#提供的工具的表现力来获得简洁清除的解决方案,以及最佳 O(n))。

此时我有以下代码,它仍然看起来很混乱,并且会对属性进行两次评估。

List<foo> elements;
private int getBest(object x)
{
  var indices = Enumerable.Range(0, elements.Count);
  return indices.Aggregate(-1, (best, next) =>
    (-1 == best || eval(x, elements[next]) > eval(x, elements[best])) ? next : best);
}

如何让这段代码变得更好?


附录:为了清晰起见,我没有将其放在代码中,但如果eval()低于某个阈值,则该元素将被丢弃。

3 个答案:

答案 0 :(得分:1)

使用LINQ这样做很有趣,但没有LINQ这样做会使它更直观:

int bestIndex = -1;
int bestResult = -1;
for(int i = 0; i < elements.Count; ++i)
{
    int currentResult = eval(x, elements[i]);
    if (currentResult > bestResult)
    {
        bestResult = currentResult;
        bestIndex = i;
    }
}

答案 1 :(得分:1)

我建议将SelectAggregate LINQ扩展方法结合使用。使用Select方法,您可以创建一个匿名类型,其中包含集合中每个项目的indexvalue。然后使用LINQ Aggregate方法,您可以缩小具有最大值的项目。我认为有些人应该这样做:

private int GetIndexOfHighestValue(IEnumerable<int> list)
{
    return list.Select((i, v) => new { Index = i, Value = v })
        .Aggregate((a, b) => (a.Value > b.Value) ? a : b)
        .Index;
}

答案 2 :(得分:0)

这样的东西可以起作用

// OOPS: This won't work because Max is defined the way it is. Always bugged me...
var result = elements.Select((e, i) => new {Element = e, Index = i}).Max(x => x.Element).Select(x => x.Index);
哦,老鼠。对。这不行。所以:让我们全力以赴:Aggregate。我们走了:

var elements = new List<int>{1, 7, 2, 5};
var result = elements.Select((e, i) => new {Element = e, Index = i})
    .Aggregate(
        new { Element = elements.First(), Index = -1}, // gotta start somewhere and Element is non-nullable according to OP
        (max, next) => (max.Element > next.Element) && max.Index >= 0 ? max : next,
        max => max.Index);

这导致1。这有帮助吗?