2

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

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

4 回答 4

2

您可以使用GroupBy

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

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

于 2013-10-31T10:50:38.873 回答
1

你可以试试这个:

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

或者

return _Objects.Where(_Object => _Object.isValid).OrderBy(_Object => _Object.Height).FirstOrDefault();
于 2013-10-31T10:48:53.103 回答
1

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

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

这将只循环一次集合。

但是,您说“我在想用 LinQ 可以更清楚地完成它。” 这是否更清楚,我让你决定。

于 2013-10-31T12:18:55.133 回答
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();
于 2013-10-31T10:52:40.350 回答