我的开发人员朋友告诉我,使用委托的循环速度要快得多,而且我想对它进行基准测试,但是我无法将它们的工作原理连接起来。
考虑以下平衡计算器。这基本上是一个帐户列表,如果它存在,则将初始值(起始余额)添加到总信用值中,并减去每个帐户的总借方值:
private static IDictionary<string, decimal> CalculateBalances(
IDictionary<string, decimal> initialValue,
IDictionary<string, decimal> credits,
IDictionary<string, decimal> debits)
{
var r = new Dictionary<string, decimal>();
foreach (var key in initialValue.Select(k => k.Key)
.Concat(credits.Select(k => k.Key))
.Concat(debits.Select(k => k.Key))
.Distinct())
{
r.Add(key,
(initialValue.ContainsKey(key) ? initialValue[key] : 0M)
+ (credits.ContainsKey(key) ? credits[key] : 0M)
- (debits.ContainsKey(key) ? debits[key] : 0M)
);
}
return r;
}
这对于中小型帐户列表相当表现,但使用委托会更快吗?坦率地说,委托逻辑似乎与我的思维过程正确地运作,因为我正在摸不着写这个。
有人能提供一种使用委托重写的方法吗?
答案 0 :(得分:5)
我假设您的朋友指的是ForEach
类上的List<T>
方法。对您的问题的简短回答是否。
等效语法为:
initialValue.Select(k => k.Key)
.Concat(credits.Select(k => k.Key))
.Concat(debits.Select(k => k.Key))
.Distinct()
.ToList()
.ForEach(var => r.Add(key,
(initialValue.ContainsKey(key) ? initialValue[key] : 0M)
+ (credits.ContainsKey(key) ? credits[key] : 0M)
- (debits.ContainsKey(key) ? debits[key] : 0M)
));
它既慢又难以阅读。委托调用比普通方法调用慢。您上面的语法更快,更容易阅读。
答案 1 :(得分:2)
有人能提供一种使用委托重写的方法吗?
但是你已经使用代表了!这就是lambda被转换成的东西。 出于性能原因,是否使用委托或者委托给循环体的问题有点奇怪,因为正在使用这么多的委托调用来生成序列的每个项目。
无论如何,Adam Robinson已经介绍了如何List.ForEach
对列表中的每个项目执行副作用以及相关的可读性和性能影响,所以我不会进入那个。
但是,如果LINQ和委托调用的边际开销不是决定因素,那么我将如何编写您的方法:
return initialValue
.Concat(credits)
.Concat(debits.Select(kvp => new KeyValuePair<string, decimal>(kvp.Key, -kvp.Value)))
.GroupBy(kvp => kvp.Key, kvp => kvp.Value)
.ToDictionary(group => group.Key, group => group.Sum());
现在它更具可读性。
答案 2 :(得分:0)
如果要使用foreach
构建新词典,Dictionary.Add
构造是正确的构造。你总是可以从现有字典中选择创建一个新字典,但速度会慢一些。
但是,关于可读性,这不是更容易吗?
private static decimal GetOrZero(this IDictionary<string,decimal> dict, string key)
{
decimal value = 0;
dict.TryGetValue(key, out value);
return value;
}
private static IDictionary<string, decimal> CalculateBalances(
IDictionary<string, decimal> initialValue,
IDictionary<string, decimal> credits,
IDictionary<string, decimal> debits)
{
var r = new Dictionary<string, decimal>();
var accounts = initialValue.Keys.Union(debits.Keys).Union(credits.Keys);
foreach (var accounts in accounts)
{
r.Add(initialValue.GetOrZero(key) + credits.GetOrZero(key) - debits.GetOrZero(key));
}
return r;
}