LINQ系列
在實務上在這記錄一些比較常用的LINQ使用的操作
public class Program
{
public static List<Student> students = new List<Student>
{
new Student{Id = "1",Name = "張三",Age = 25, Score = 90,ClassId = "101"},
new Student{Id = "2",Name = "兆四",Age = 33, Score = 70, ClassId = "101"},
new Student{Id = "3",Name = "兆四",Age =33, Score = 77,ClassId = "102"},
new Student{Id = "4",Name = "張三",Age = 25, Score = 65,ClassId = "102"},
new Student{Id = "5",Name = "張三",Age = 27, Score = 72,ClassId = "103"},
new Student{Id = "6",Name = "李六",Age = 28, Score = 66,ClassId = "103"},
};
public static List<StudentClass> studentClass = new List<StudentClass>
{
new StudentClass{ClassId = "101",ClassName = "一年一班" ,},
new StudentClass{ClassId = "102",ClassName = "一年二班"},
new StudentClass{ClassId = "103",ClassName = "一年三班"},
new StudentClass{ClassId = "104",ClassName = "一年四班"},
};
private static void Main(string[] args)
{
//找到第一位名叫張三的學生
var qryData1 = students.Where(x => x.Name == "張三").FirstOrDefault();
Console.WriteLine("");
Console.WriteLine($"Name={qryData1.Name},Age={qryData1.Age}");
//找出超過三十歲的學生
var qryData2 = students.Where(x => x.Age > 30).ToList();
foreach (var i in qryData2)
{
Console.WriteLine(i.Name);
}
//由小到大
Console.WriteLine("");
Console.WriteLine("Id排序");
var qryData3 = students.OrderBy(x => x.Id);
foreach (var i in qryData3)
{
Console.WriteLine(i.Id);
}
// 由大到小
Console.WriteLine("");
Console.WriteLine("Id排序 Desc");
var qryData4 = students.OrderByDescending(x => x.Id);
foreach (var i in qryData4)
{
Console.WriteLine(i.Id);
}
//Join用法
Console.WriteLine("");
Console.WriteLine("Join 用法");
var qryJoin = studentClass.Join(students,
c => c.ClassId,
s => s.ClassId,
(c, s) => new
{
ClassName = c.ClassName,
Name = s.Name,
ClassId = c.ClassId
}).OrderBy(cs => cs.ClassId).Where(cs => cs.ClassName == "一年一班");
foreach (var i in qryJoin)
{
Console.WriteLine($"班級:{i.ClassName} 名稱:{i.ClassName} 姓名:{i.Name}");
}
//Left Join
Console.WriteLine("");
Console.WriteLine("GroupJoin 用法1");
var qryLeftJoin1 = studentClass.GroupJoin(students,
c => c.ClassId,
s => s.ClassId,
(c, s) => new
{
ClassId = c.ClassId,
ClassName = c.ClassName,
s,
}).SelectMany(x => x.s.DefaultIfEmpty(), //要使用DefaultIfEmpty 才能轉換成Left Join
(c, s) => new
{
ClassName = c.ClassName,
Name = (s == null ? "" : s.Name)
});
foreach (var i in qryLeftJoin1)
{
Console.WriteLine($"班級:{i.ClassName} 學生姓名:{i.Name}");
}
Console.WriteLine("");
Console.WriteLine("GroupJoin 用法2");
var qryLeftJoin2 = studentClass.GroupJoin(students,
c => c.ClassId,
s => s.ClassId,
(c, s) => new
{
ClassName = c.ClassName,
s = s
});
foreach (var i in qryLeftJoin2)
{
Console.WriteLine($"班級:{i.ClassName}");
foreach (var s in i.s)
{
Console.WriteLine($"姓名:{s.Name}");
}
}
//Group By用法
Console.WriteLine("");
Console.WriteLine("Name Group");
var result1 = students.GroupBy(x => new { x.Name }).Select(x =>
new Student { Name = x.Key.Name }).ToList();
foreach (var i in result1)
{
Console.WriteLine($"Name={i.Name}");
}
Console.WriteLine("");
Console.WriteLine("Name Group Age Min Score Min");
var result2 = students.GroupBy(x => new { x.Name, }).Select(x => new Student
{
Name = x.Key.Name,
Age = x.Min(y => y.Age),
Score = x.Min(y => y.Score)
}).ToList();
foreach (var i in result2)
{
Console.WriteLine($"Name={i.Name},Age={i.Age},Score={i.Score}");
}
Console.WriteLine("");
Console.WriteLine("Name Group Age Max Score Max");
var result3 = students.GroupBy(x => new { x.Name, }).Select(x => new Student
{
Name = x.Key.Name,
Age = x.Max(y => y.Age),
Score = x.Max(y => y.Score)
}).ToList();
foreach (var i in result3)
{
Console.WriteLine($"Name={i.Name},Age={i.Age},Score={i.Score}");
}
Console.WriteLine("");
Console.WriteLine("Name Group Age Max Score Max");
var result4 = students.GroupBy(x => new { x.Name, }).Select(x => new Student
{
Name = x.Key.Name,
Age = x.Sum(y => y.Age),
Score = x.Max(y => y.Score)
}).ToList();
foreach (var i in result4)
{
Console.WriteLine($"Name={i.Name},Age={i.Age},Score={i.Score}");
}
Console.WriteLine("");
Console.WriteLine("Name Group Age Sum Score Sum");
var result5 = students.GroupBy(x => new { x.Name }).Select(x => new Student
{
Name = x.Key.Name,
Age = x.Sum(y => y.Age),
Score = x.Sum(y => y.Score)
}).ToList();
foreach (var i in result5)
{
Console.WriteLine($"Name={i.Name},Age={i.Age},Score={i.Score}");
}
}
}
public class Student
{
public string Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public int Score { get; set; }
public string ClassId { get; set; }
}
public class StudentClass
{
public string ClassId { get; set; }
public string ClassName { get; set; }
}
上面的是專門記錄比較常用在LINQ的常用部分 ,因為
早期學SQL的時候也是從最基本最常用的SELECT, FROM,
WHERE ,ORDER BY ,GROUP BY,INNER JOIN ,LEFT JOIN
這幾個很常用,可以應付很多的狀況。
註記:那關於ToLookup與GruopBy差異?,在延遲執行
Sample如下
var sampleGroup = students.GroupBy(s => s.ClassId);
var sampleToLookup = students.ToLookup(s => s.ClassId);
students.RemoveAll(s => true);
Console.WriteLine($"------GroupBy Sample------");
foreach (var i in sampleGroup)
{
Console.WriteLine($"classid={i.Key}");
foreach (var item in i)
{
Console.WriteLine($"name={item.Name},score={item.Score}");
}
}
Console.WriteLine($"------ToLookup Sample------");
foreach (var i in sampleToLookup)
{
Console.WriteLine($"classid={i.Key}");
foreach (var item in i)
{
Console.WriteLine($"name={item.Name},score={item.Score}");
}
}
主要是GroupBy會等首次抓資料內容時才跑查詢,在之前就已經Clear了,因為資料清空,這樣結果
就是延遲執行所造成。
補充:如果要用類似WHERE IN的語法如下:
List<temp> tmps = new List<temp>
{
new temp(){Seq = 1,Qty = 1,Amt = 200},
new temp(){Seq = 1,Qty = 2,Amt = 250},
new temp(){Seq = 2,Qty = 1,Amt = 250},
new temp(){Seq = 3,Qty = 3,Amt = 250},
new temp(){Seq = 3,Qty = 2,Amt = 450},
};
var seqlist = new List<int>(){1,3};
var qry = tmps.Where(x => seqlist.Contains(x.Seq)).ToList();
我針對序號1和3進行查詢,就會撈到四筆資料
案例:如果要把1跟3的序號資料,單價*數量並加總起來該怎麼做呢?
List<temp> tmps = new List<temp>
{
new temp(){Seq = 1,Qty = 1,Amt = 200},
new temp(){Seq = 1,Qty = 2,Amt = 250},
new temp(){Seq = 2,Qty = 1,Amt = 250},
new temp(){Seq = 3,Qty = 3,Amt = 250},
new temp(){Seq = 3,Qty = 2,Amt = 450},
};
var seqlist = new List<int>(){1,3};
var qry = tmps.Where(x => seqlist.Contains(x.Seq)).ToList();
decimal total = qry.GroupBy(x => new {x.Seq}).Select(x => new
{
Amt = x.Sum(y=> y.Qty * y.Amt)
}).ToList().Sum(x=> x.Amt);
上述就能把你要的東西給加總起來。
之前有記錄了常用LINQ應用部分,這次是稍微複雜一點就是,我要把每個部門,找出分數最高的那一筆資料出來,該怎麼做呢?
解法一
List<Depart> departs = new List<Depart>
{
new Depart(){ Id=1,Name = "業務部"},
new Depart(){ Id=2,Name = "行銷部"},
new Depart(){ Id=3,Name = "生產部"}
};
List<ScoreReport> reports = new List<ScoreReport>
{
new ScoreReport(){No = 1,Id=1,Score = 60},
new ScoreReport(){No = 2,Id=1,Score = 70},
new ScoreReport(){No = 3,Id=1,Score = 65},
new ScoreReport(){No = 4,Id=2,Score = 30},
new ScoreReport(){No = 5,Id=2,Score = 25},
new ScoreReport(){No = 6,Id=2,Score = 60},
new ScoreReport(){No = 7,Id=3,Score = 40},
new ScoreReport(){No = 8,Id=3,Score = 50},
new ScoreReport(){No = 9,Id=3,Score = 85},
};
var qry = departs.Join(reports,
depart => depart.Id,
report => report.Id, (d,r) => new {d, r })
.GroupBy(g => new { g.d.Name})
.Select(g => new
{
Name = g.Key.Name,
Score = g.Max(p => p.r.Score)
}).ToList();
foreach (var item in qry)
{
Console.WriteLine(item.Name + " " + item.Score);
}
解法一有個缺點是它只能針對彙整的屬性來顯示。
所以這時候延伸出解法二
var qry2 = departs.Join(reports,
depart => depart.Id,
report => report.Id, (d, r) => new { d, r })
.GroupBy(g => new { g.d.Name })
.Select(g => new { su= g.OrderByDescending(i => i.r.Score)})
.Select(x=>x.su.FirstOrDefault()).ToList();
foreach (var item in qry2)
{
Console.WriteLine(item.d.Name + " " + item.r.Score);
}
解法二是先把分數進行排序後,找出最大的那一筆資料出來。
近期遇到英文排序的問題,若是要按照大寫排序和小寫排序,可考慮用以下用法
List<string> strArr = new List<string>() { "D","d","A", "a", "B", "b", "C", "c" };
strArr = strArr.OrderBy(x => x, StringComparer.Ordinal).ToList();
元哥的筆記