繁体   English   中英

C#Lambda表达式复杂度

[英]c# lambda expression complexity

关于lambda表达式的一个简单问题

我想在以下代码中获得所有交易的平均值。 我正在使用的公式是((价格1 *数量1+(价格2 *数量2).... +(价格n *数量n)/(数量1+数量2 + ... +数量n)

在下面的代码中,我使用求和函数计算(price * qty)的总和,复杂度为O(n),再一次累加所有数量的复杂度为O(n)。 因此,有什么方法可以使用复杂度找到两者的总和。O(n)表示可以计算两个结果的单个lambda表达式。

使用for循环,我可以计算O(n)复杂度的两个结果。

class Program
{
    static void Main(string[] args)
    {
        List<Trade> trades = new List<Trade>()
        {
            new Trade() {price=2,qty=2},
            new Trade() {price=3,qty=3}
        };

         ///using lambda
        int price = trades.Sum(x => x.price * x.qty);
        int qty = trades.Sum(x => x.qty);

        ///using for loop
        int totalPriceQty=0, totalQty=0;

        for (int i = 0; i < trades.Count; ++i)
        {
            totalPriceQty += trades[i].price * trades[i].qty;
            totalQty += trades[i].qty;
        }
        Console.WriteLine("Average {0}", qty != 0 ? price / qty : 0);
        Console.Read();
    }
}

class Trade
{
    public int price;
    public int qty;
}

编辑:我知道该系数不计算在内。 让我用lambda来表述一下这个问题,即使用lambda我们将遍历列表中的每个元素两次,而使用for循环我们将仅遍历每个元素一次。 lambda是否有解决方案,因此不必两次遍历列表元素?

Big-O复杂度不考虑常数系数。 O(n)+ O(n)仍为O(n)。

如果确定要在lambda中使用它,下面是使用Aggregate运算符的示例。 它看起来很虚构,我不建议在传统的for循环中使用它。

var result = trades.Aggregate(
    Tuple.Create(0, 0),
    (acc, trade) => 
        Tuple.Create(acc.Item1 + trade.price * trade.qty, acc.Item2 + trade.qty));

int totalPrice = result.Item1;
int totalQuantity = result.Item2;

如前所述,无论您迭代一次还是两次,Big-O都保持不变。 如果您只想使用Linq进行一次迭代,就可以使用自定义聚合器(因为要还原为相同的属性,我们可以仅使用Trade实例进行聚合):

var ag = trades.Aggregate(new Trade(), 
                          (agg, trade) => 
                          { 
                            agg.price += trade.price * trade.qty; 
                            agg.qty += trade.qty; 
                            return agg; 
                          });
int price = ag.price;
int qty = ag.qty;

在这一点上,我个人将只使用一个foreach循环或您已经拥有的简单lambda-除非此处的性能至关重要(测量一下!)

为了扩展BrokenGlass的答案,您还可以使用匿名类型作为聚合器,如下所示:

var result = trades.Aggregate( 
                 new { TotalValue = 0L, TotalQuantity = 0L }, 
                 (acc, trade) => new 
                 { 
                     TotalValue = acc.TotalValue + trade.price, 
                     TotalQuantity = acc.TotalQuantity + trade.qty
                 }
             );

这种方法有两个小缺点:

  1. 如果您对大量交易(或大笔交易)进行这种计算,则可能溢出会跟踪交易总价值和总股本的int 这种方法允许你指定long为您的数据类型(所以它会需要更长的时间溢出)。

  2. 与仅返回Trade对象相比,从该聚合中获取的对象将具有更有意义的属性。

最大的缺点是,看起来有点奇怪。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM