我有一个定义为
的类class P
{
public List<P> children;
public int Val1;
public int Val2;
}
正如您所看到的,该类具有同一类的对象列表。我实例化该类并填写列表:
P myp = new P { children = new List<P> {new P {Val1 = 1, Val2 = 1}, new P {Val1 = 2, Val2 = 2}}};
现在,如果我想总结儿童字段的值并将它们放在适当的父字段中,我可以做到
foreach (var p in myp.children)
{
myp.Val1 += p.Val1;
myp.Val2 += p.Val2;
}
这似乎很有效,但我可以做得更好
myp.Val1 = myp.children.Sum(p => p.Val1);
myp.Val2 = myp.children.Sum(p => p.Val2);
更具可读性,但两次遍历列表。
有没有一种美丽而高效的方式来做到这一点?还是我坚持使用foreach?
答案 0 :(得分:4)
有时候我们开发人员会对最愚蠢的事情产生神经质。我去过那里太多了。我认为没有任何理由改变它。
不过,如果你愿意,这是一个想法:
class P
{
public List<P> children;
public int Val1;
public int Val2;
public void Add( P p )
{
this.Val1 += p.Val1;
this.Val2 += p.Val2;
}
}
然后你可以做......
myp.children.ForEach( myp.Add );
答案 1 :(得分:3)
如果表演与您的情况相关,并且您要重复使用两个值的总和,则可以编写扩展方法:
public static void SumMultiple<T>(this IEnumerable<T> x, Func<T, int> selector1, Func<T, int> selector2, out int a, out int b)
{
a = b = 0;
foreach (var item in x)
{
a += selector1(item);
b += selector2(item);
}
}
测试代码:
int val1, val2;
collection.SumMultiple(a => a.A, b => b.B, out val1, out val2);
Console.WriteLine("Val1 is {0}, Val2 is {1}", val1, val2);
否则我认为foreach循环是受欢迎的。
答案 2 :(得分:3)
除非我认为是两个慢的我喜欢
myp.Val1 = myp.children.Sum(p => p.Val1);
myp.Val2 = myp.children.Sum(p => p.Val2);
因为它更容易移动代码和反射器代码。
将许多操作组合到同一个循环中可能会更快,(但通常你并不关心速度那么多),但是这使得将代码提取到一个单独的方法中变得更加困难,而这个方法是大多数重构的基础。
请记住,现在将数据从主内存读取到处理器缓存需要花费更长时间(通常为100倍或更多),然后处理器会读取已在其缓存中的数据。在第二次迭代中,相同数据的时间通常比第一次少得多。
如果您使用分析器,请非常小心,因为大多数分析器都没有获得处理器缓存的效果,分析器也会使用其时序代码填充处理器缓存。
答案 3 :(得分:2)
也许是相同的foreach
(虽然看起来对我很不错)但是用List.ForEach方法写的会这样做:
myp.children.ForEach(p => { myp.Val1 += p.Val1; myp.Val2 += p.Val2; });
答案 4 :(得分:1)
对我而言,第一种方法看起来更干净,更具可读性和更高效(两次通过列表并在第二次创建2个lamda)
答案 5 :(得分:1)
我想每个人都很好。一次迭代,易于阅读和理解。但下面是一个奇怪的代码,它使用Sum。
myp.Val1 = myp.children.Sum(p => { myp.Val2 += p.Val2; return p.Val1; });