[英]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
}
);
这种方法有两个小缺点:
如果您对大量交易(或大笔交易)进行这种计算,则可能溢出会跟踪交易总价值和总股本的int
。 这种方法允许你指定long
为您的数据类型(所以它会需要更长的时间溢出)。
与仅返回Trade
对象相比,从该聚合中获取的对象将具有更有意义的属性。
最大的缺点是,看起来有点奇怪。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.