2017-05-09 62 views
0

我不得不根据3个键值对某些记录进行分组,然后总结组中的其他值。但后来才意识到LINQ的性能比每个都要差。所以请帮助转换linq码为正常每个需要将LINQ(GROUP BY和sum)转换为foreach逻辑。 C#

List<Test> testList= new List<Test>(); 
    testList.GroupBy(ab => new 
    { 
    ab.Property1, 
    ab.Property2, 
    ab.Property3       
    }).Select(a => new Test 
      { 
      Property1= a.Key.Property1, 
      Property2= a.Key.Property2, 
      Property3= a.Key.Property3,    
      Property4= a.Select(ab => ab.Property4).FirstOrDefault(), 
      Property5= a.Sum(ab => ab.Property5), 
      Property6= a.Sum(ab => ab.Property6), 
      Property7= a.Sum(ab => ab.Property7), 
      Property8= a.Sum(ab => ab.Property8), 
      }); 
+0

性能与时间。你执行过多少次?可以缓存吗? –

+0

该列表正在从for循环(10k)次内执行的数据库中获取。必须将LINQ的东西转换为每个循环使用的排序逻辑 – ashwinrajagopal

+1

Linq只比foreach慢一点,你需要比可读代码的性能多少? – EpicKip

回答

0

逐行它应该是:

List<Test> testList = new List<Test>(); 

// string, string, string = Property1, Property2, Property3 
var dict = new Dictionary<Tuple<string, string, string>, List<Test>>(); 

foreach (var el in testList) 
{ 
    List<Test> list; 

    var key = Tuple.Create(el.Property1, el.Property2, el.Property3); 

    if (!dict.TryGetValue(key, out list)) 
    { 
     list = new List<Test>(); 
     dict.Add(key, list); 
    } 

    list.Add(el); 
} 

var output = new List<Test>(dict.Count); 

foreach (var kv in dict) 
{ 
    var list = kv.Value; 

    var el = new Test 
    { 
     Property1 = kv.Key.Item1, 
     Property2 = kv.Key.Item2, 
     Property3 = kv.Key.Item3, 
     Property4 = list[0].Property4, 
    }; 

    output.Add(el); 

    for (int i = 0; i < list.Count; i++) 
    { 
     el.Property5 += list[i].Property5; 
     el.Property6 += list[i].Property6; 
     el.Property7 += list[i].Property7; 
     el.Property8 += list[i].Property8; 
    } 
} 

唯一的“真正的”这里的优点是,内for周期为Sum部分是单for而不是正在使用的四个单独的for四个单独的Sum

但还有另一种方式做到这一点,那就是从LINQ不同...

List<Test> testList = new List<Test>(); 

// string, string, string = Property1, Property2, Property3 
var dict = new Dictionary<Tuple<string, string, string>, Test>(); 

foreach (var el in testList) 
{ 
    Test el2; 

    var key = Tuple.Create(el.Property1, el.Property2, el.Property3); 

    if (!dict.TryGetValue(key, out el2)) 
    { 
     el2 = new Test 
     { 
      Property1 = el.Property1, 
      Property2 = el.Property2, 
      Property3 = el.Property3, 
      Property4 = el.Property4, 
     }; 

     dict.Add(key, el2); 
    } 

    el2.Property5 += el.Property5; 
    el2.Property6 += el.Property6; 
    el2.Property7 += el.Property7; 
    el2.Property8 += el.Property8; 
} 

var output = dict.Values.ToList(); 

这里我们结合两个foreach周期,我们取下内for周期。

现在,除非您正在处理数百万条记录,否则我认为这两个解决方案之间的差异不会太大。

请注意,我的代码和LINQ代码之间的输出存在重要区别:当在IEnumerable上使用时,GroupBy运算符确保组的排序与输入中的相同(因此第一个元素将生成第一个组,下一个具有不同键的元素将生成第二个组,等等)。使用Dictionary<,>这不会发生。输出的顺序没有定义,并且是“随机的”。

+0

第一个建议不包括任何内容。 – NetMage

+0

@NetMage如果你在集合中添加了一些元素,它将正确地求和:https://ideone.com/pWVDzD – xanatos

+0

对不起,我的错误。没有注意到滚动条! – NetMage