2017-05-09 60 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