# LINQ 的一點優化,與 foreach、for 比較
###### tags: `.Net` `LINQ`
有一天同仁撰寫了一段程式,但寫出來測試覺得執行時間過久。於是我們就一同探討
程式如下:
``` .net
List<student> studentCollection = await client.GetDatabase("sample_training").GetCollection<student>("grades").AsQueryable().ToListAsync();
Dictionary<double, List<student>> studentDic = new Dictionary<double, List<student>>();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Restart();
stopWatch.Start();
List<double> studentIds = studentCollection.Select(s => s.student_id).Distinct().ToList();
studentIds.ForEach(item =>
{
studentDic.Add(item, studentCollection.Where(f => f.student_id == item).ToList());
}
stopWatch.Stop();
Console.WriteLine("First LINQ Version: " + stopWatch.Elapsed.TotalMilliseconds);
```
這段程式本身看起來是沒有甚麼太大的問題,將不重複的 student_id 取出,並依序做事。
但假設這個集合本身是一個很巨量的時候,就會遇到執行不佳的問題(將資料筆數拉到30萬)
測試的數據如下:

從上面的圖片可以看出,兩者的差異是非常的巨大
於是就有一說是 LINQ 這一類 Lambda 語法的鍋,必須使用傳統的迴圈進行處理。
接著進行調整如下:
``` c#
Dictionary<double, List<student>> studentsDic = new Dictionary<double, List<student>>();
foreach (var item in studentCollection)
{
if (studentsDic.ContainsKey(item.student_id))
{
studentsDic[item.student_id].Add(item);
}
else
{
studentsDic.Add(item.student_id, new List<student>());
}
}
```
但覺得 LINQ 已經推出已久,應該是在使用上有一些誤用。
接著調整如下:
```
studentDic = studentCollection.GroupBy(x => x.student_id)
.ToDictionary(x => x.Key, x => x.ToList());
```
針對 student_id 做 GroupBy 接著 ToDictionary。讓整個語法跟可讀性有很大的改進,不過 foreach、for 也有效能上的比較,下面也有使用 for 進行調整的寫法。
調整如下:
```
for (int i = 0; i < studentCollection.Count; i++)
{
var item = studentCollection[i];
if (studentDic.ContainsKey(item.student_id))
{
studentDic[item.student_id].Add(item);
}
else
{
studentDic.Add(item.student_id, new List<student>());
}
}
```
整個最後測試的數據如下:

最後可以看出,LINQ 如果好好調整的話,效能是不會大幅輸 foreach、for