LINQ Min / Max和最小化迭代

时间:2017-11-27 22:08:02

标签: c# linq c#-7.0

我正在编写一个带有一系列System.Windows.Point的函数,并返回一个ValueTuple,其中包含所有点的边界X和Y值。这是为了确定图轴的标签。

我试图将我执行的列表的迭代次数最小化为一次。经过大量的谷歌搜索,我已经适应(阅读:"复制")下面的方法,我被告知将这样做。但我不确定如何验证这一事实。我想知道是否有人更熟悉LINQ

  1. 确认以下功能确实只会迭代列表一次,即使它计算了4个不同的值
  2. 如果是这样,请向我解释这是怎么回事。因为在我看来,正在构建的匿名类型调用" Min"并且" Max"在给定列表上每次两次。为什么不会导致4次迭代?
  3. 或许甚至可以解释我如何自己验证发生的迭代次数,以便将来我不需要问这些问题。我不明白该怎么做。
  4. 我的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);
        }
    

1 个答案:

答案 0 :(得分:4)

  

确认以下功能确实只会迭代列表一次,即使它计算了4个不同的值

否 - 原始列表将有效地迭代4次。你正在创建一个&#34; null&#34;分组将包装原始集合,以便您可以&#34;项目&#34;集合到一个对象。因为你在&#34;分组&#34;上调用了4个linq函数。 - 原始列表将重复4次。它在功能上等同于:

foreach

如果这对您来说是个问题,找到边界的惯用方法是使用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 }; 循环并手动跟踪最小和最大x和y坐标。这将是一个相对较短的函数,并将迭代次数减少75%:

Aggregate

可以使用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); }); 循环查找带有lambda的分钟和最大值:

import web

urls = {
    '/', 'home',
    '/register', 'registerclick'
}

render = web.template.render("views/templates", base="MainLayout")
app = web.application(urls, globals())

# Classes/Routes

class home:
    def GET(self):
        return render.home()

class registerclick:
    def GET(self):
        return render.register()

if __name__ == "__main__":
    app.run()

但聚合器将为源集合中的每个对象创建一个对象,另外一个用于&#34; initial&#34;宾语。因此列表只会迭代一次,但会创建多个临时对象,从而增加了需要GC的内存量。