[英]LINQ Min/Max and minimizing iterations
我正在编写一个函数,该函数需要一系列System.Windows.Point并返回带有所有点的边界X和Y值的ValueTuple。 这旨在确定图形轴的标签。
我试图将执行的列表的迭代次数减至最少。 经过大量的谷歌搜索,我已经采用了一种类似下面的方法(被告知:“已复制”),我被告知可以做到这一点。 但是我不确定如何验证这一事实。 我想知道是否更熟悉LINQ的人可以
我的LINQ-Fu还不牢固。
谢谢
/// <summary>
/// X and Y axis boundaries in the form of a System.ValueTuple.
/// </summary>
public (double MinX, double MaxX, double MinY, double MaxY)
GetBounds(List<System.Windows.Point> pts)
{
// Calculate the bounds with a LINQ statement. Is this one iteration or many?
var a = pts.GroupBy(i => 1).Select(
pp => new
{
MinY = pp.Min(p => p.Y),
MaxY = pp.Max(p => p.Y),
MinX = pp.Min(p => p.X),
MaxX = pp.Max(p => p.X)
}).FirstOrDefault();
return a != null ? (a.MinX, a.MaxX, a.MinY, a.MaxY) : (0, 0, 0, 0);
}
确认以下函数确实只对列表进行一次迭代,即使它正在计算4个不同的值
否-原始清单将有效地重复4次。 您正在创建将包装原始集合的“空”分组,以便可以将集合“投影”到单个对象。 由于您在“分组”上调用了4个linq函数-原始列表将被迭代4次。 它在功能上等同于:
var a = new
{
MinY = pts.Min(p => p.Y),
MaxY = pts.Max(p => p.Y),
MinX = pts.Min(p => p.X),
MaxX = pts.Max(p => p.X)
};
如果这对您来说是个问题 ,查找边界的惯用方式是使用foreach
循环并手动跟踪最小和最大x和y坐标。 这将是一个相对简短的函数,并将迭代次数减少75%:
int MinX, MaxX, MinY, MaxY;
MaxX = MaxY = Int.MinValue;
MinX = MinY = Int.MaxValue;
foreach(Point p in pts)
{
MinX = Math.Min(p.X, MinX);
MaxX = Math.Max(p.X, MaxX);
MinY = Math.Min(p.Y, MinY);
MaxY = Math.Max(p.Y, MaxY);
}
var a = new
{
MinY,
MaxY,
MinX,
MaxX
};
您可以使用Aggregate
循环查找带有lambda的最小值和最大值:
var a = pts.Aggregate(
new {
MinX = int.MaxValue,
MaxX = int.MinValue,
MinY = int.MaxValue,
MaxY = int.MinValue
},
(acc, p) => new {
MinX = Math.Min(p.X, acc.MinX);
MaxX = Math.Max(p.X, acc.MaxX);
MinY = Math.Min(p.Y, acc.MinY);
MaxY = Math.Max(p.Y, acc.MaxY);
});
但是聚合器将为源集合中的每个对象创建一个对象,再为“初始”对象创建一个对象。 因此,列表只会被迭代一次,但是会创建多个临时对象,从而增加了需要进行GC处理的内存量。
您在此处使用的方法至少对输入值进行五次迭代(一次将它们“分组”,然后对每个最小值/最大值进行一次迭代),这是进行操作的一种极其奇怪的方法。
当您要收集一组值并将其压缩为一个值时,首选方法是.Aggregate
(在其他语言中也称为reduce
或fold
)。
在您的情况下,您可以这样做。 它应该只对您的集合进行一次迭代:
public static (double minX, double maxX, double minY, double maxY)
GetBounds(List<Point> pts)
{
return pts.Aggregate(
(Int32.MaxValue, Int32.MinValue, Integer.MaxValue, Int32.MinValue),
(acc, point) =>
(
Math.Min(point.X, acc.Item1),
Math.Max(point.X, acc.Item2),
Math.Min(point.Y, acc.Item3),
Math.Max(point.Y, acc.Item4)
));
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.