如何在最小和附加条件下优化LINQ

时间:2013-10-31 10:46:20

标签: c# performance linq

假设我们有一个对象列表(为了更清楚,没有使用属性等等)

public class SomeObject{
    public bool IsValid;
    public int Height;
}

List<SomeObject> objects = new List<SomeObject>(); 

现在我只想要一个列表中的值,它既有效又具有最低的高度。

经典地我会使用像:

SomeObject temp;
foreach(SomeObject so in objects)
{
    if(so.IsValid)
    {
        if (null == temp) 
            temp = so;
        else if (temp.Height > so.Height)
            temp = so;
    }
}
return temp;

我在想,LinQ可以更清楚地完成它。

我想到的第一种方法是:

List<SomeObject> sos =  objects.Where(obj => obj.IsValid);
if(sos.Count>0)
{
     return sos.OrderBy(obj => obj.Height).FirstOrDefault();
}

但后来我想:在foreach方法中,我将一次性地通过列表。使用Linq我会在列表中进行一次过滤,有一次订购,即使我不需要完成订单列表。

会像

return objects.OrderBy(obj => obj.Height).FirstOrDefault(o => o.IsValid);

列表中还有两次?

这可以以某种方式进行优化,以便linw也只需要在列表中运行一次吗?

4 个答案:

答案 0 :(得分:2)

您可以使用GroupBy

IEnumerable<SomeObject> validHighestHeights = objects
            .Where(o => o.IsValid)
            .GroupBy(o => o.Height)
            .OrderByDescending(g => g.Key)
            .First();

此组包含所有高度最高的有效对象。

答案 1 :(得分:1)

你可以尝试这个:

return (from _Object in Objects Where _Object.isValid OrderBy _Object.Height).FirstOrDefault();

return _Objects.Where(_Object => _Object.isValid).OrderBy(_Object => _Object.Height).FirstOrDefault();

答案 2 :(得分:1)

使用Linq执行此操作的最有效方法如下:

var result = objects.Aggregate(
    default(SomeObject),
    (acc, current) =>
        !current.IsValid ? acc :
        acc == null ? current :
        current.Height < acc.Height ? current :
        acc);

这只会在集合上循环一次。

然而,你说“我认为可以用LinQ更清楚地完成它。”无论这是否更清楚,我都会由你决定。

答案 3 :(得分:0)

  

会像

return objects.OrderBy(obj => obj.Height).FirstOrDefault(o => o.IsValid);
     

列表中还有两次?

仅在最坏的情况下,第一个有效对象是obj.Height的最后一个有效对象(或者没有找到)。只要找到有效元素,就会停止使用FirstOrDefault迭代集合。

  

这可以以某种方式进行优化,因此linw也只需要运行   一次通过清单?

我担心你必须制作自己的扩展方法。考虑到我上面写的内容,我认为它非常优化。

**更新* *

实际上,以下内容会更快一些,因为我们会避免对无效项进行排序:

return object.Where(o => o.IsValid).OrderBy(o => o.Height).FirstOrDefault();