假设我们有一个对象列表(为了更清楚,没有使用属性等等)
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也只需要在列表中运行一次吗?
答案 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();