使用最大属性值在Enumerable中查找项目

时间:2014-03-31 00:39:39

标签: c# foreach max enumerable

我正在为C#中的AI比赛写一个条目,我正在寻找一种更优雅的方式来搜索项目。 (我对嵌入式C编程更熟悉,但我更喜欢C#进行人工智能竞赛。)

比赛服务器使用dmcs编译条目,即.Net framework 4.0;我使用Visual Studio Express 2013进行测试。

我尝试搜索列表中的项目,其中参数的最大值也符合某个先决条件。但是,我不想要最大值,我想要具有最大值的项目。

这是我使用foreach循环执行我想要的原始代码:

List<Region> myList = new List<Region>();

// ...
// myList gets populated with elements
// ...

Region biggest = null;
int biggestSize = -1;

foreach (Region r in myList)
{
    // We only want elements that are eligible for expansion
    if (r.EligibleForExpansion())
    {
        if (r.Size > biggestSize)
        {
            biggest = r;
            biggestSize = r.Size;
        }
    }
}

return biggest; // I want the biggest Region, not the Size of the biggest region.

我试图找到一种更优雅的方式来做到这一点,所以我的代码中没有foreach循环。我试过这个:

return myList.Max(delegate(Region r) { if (r.EligibleForExpansion()) return r.Size; else return -1; });

然而,它返回最大区域的Size值,而不是最大的Region本身(这就是我需要的)。

我知道如果没有Region满足要求,我的foreach代码将返回null,而Max代码将给-1(或任何不满足要求的Region);我可以处理任何一种方式。

我不认为我可以让Region IC比较;我有很多区域对象的搜索,我需要在不同的时间按不同的参数排序,因此比较函数在不同的搜索中会有所不同。

我可以将我的foreach代码包装在一个静态函数中,并在我需要搜索的地方调用它,但似乎应该有更优雅的方法在C#中执行此操作。

3 个答案:

答案 0 :(得分:4)

使用MaxBy from moreLINQ library

public static TSource MaxBy<TSource, TKey>(this IEnumerable<TSource> source,
    Func<TSource, TKey> selector)
{
    return source.MaxBy(selector, Comparer<TKey>.Default);
}

public static TSource MaxBy<TSource, TKey>(this IEnumerable<TSource> source,
    Func<TSource, TKey> selector, IComparer<TKey> comparer)
{
    if (source == null) throw new ArgumentNullException("source");
    if (selector == null) throw new ArgumentNullException("selector");
    if (comparer == null) throw new ArgumentNullException("comparer");
    using (var sourceIterator = source.GetEnumerator())
    {
        if (!sourceIterator.MoveNext())
        {
            throw new InvalidOperationException("Sequence contains no elements");
        }
        var max = sourceIterator.Current;
        var maxKey = selector(max);
        while (sourceIterator.MoveNext())
        {
            var candidate = sourceIterator.Current;
            var candidateProjected = selector(candidate);
            if (comparer.Compare(candidateProjected, maxKey) > 0)
            {
                max = candidate;
                maxKey = candidateProjected;
            }
        }
        return max;
    }
}
像那样:

var item = myList.Where(x => x.EligibleForExpansion())
                 .MaxBy(x => x.Size);

答案 1 :(得分:2)

这个怎么样?

myList.Where(r => r.EligibleForExpansion).OrderBy(r => r.Size).LastOrDefault()

答案 2 :(得分:1)

您可以使用Aggregate开箱即用:

        var item = myList
            .Where(r => r.EligibleForExpansion())
            .Aggregate((Region)null, (max, cur) => (max == null ? cur : cur.Size > max.Size ? cur : max));

如果Region是一个值类型(它不是),你可以将初始值包装在一个可空的值中,并为空列表获取一个空值:

        var item = myList
            .Where(r => r.EligibleForExpansion())
            .Aggregate((Region?)null, (max, cur) => (max == null ? cur : cur.Size > max.Value.Size ? cur : max));