foreach vs sum for multiple fields

时间:2011-09-09 09:22:22

标签: c# .net performance linq

我有一个定义为

的类
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?

6 个答案:

答案 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; });