在說明用法之后,先要弄點數據。
class Product { public int ID { get; set; } public string Name { get; set; } public string Region { get; set; } public decimal Price { get; set; } public bool IsFavorite { get; set; } } List<Product> products = new List<Product> { new Product { ID=1, Name="路易十八比薩餅", Region="意大利", Price=79961, IsFavorite = false }, new Product { ID=2, Name="澳洲胡桃", Region="澳洲", Price=195, IsFavorite = false }, new Product { ID=3, Name="Almas魚子醬", Region="伊朗", Price=129950, IsFavorite = false }, new Product { ID=4, Name="和牛肉", Region="日本", Price=3250, IsFavorite = true }, new Product { ID=5, Name="麝香貓咖啡豆", Region="印尼", Price=2000, IsFavorite = true }, new Product { ID=6, Name="大紅袍茶葉", Region="中國", Price=208000, IsFavorite = true }, new Product { ID=7, Name="Kona Nigari礦泉水", Region="美國", Price=13000, IsFavorite = true }, new Product { ID=8, Name="Diva伏特加", Region="北歐", Price=6500, IsFavorite = false }, new Product { ID=9, Name="番紅花的雄蕊", Region="地中海", Price=38986, IsFavorite = false }, };
一、ALL和ANY
bool allChina = products.All(p => p.Region == "中國");//所有項Region都要是中國,結果:False bool anyChina = products.Any(p => p.Region == "中國");//某一項Region是中國,結果:True
二、聚集
int countIdGreater5 = products.Count(p => p.ID > 5);//ID大於5的記錄數,結果:4 decimal maxPrice = products.Max(p => p.Price);//金額最高,結果:208000 int minId = products.Min(p => p.ID);//編號最小,結果:1 decimal avgPrice = products.Average(p => p.Price);//金額平均值,結果:53538 decimal sumPrice = products.Sum(p => p.Price);//金額總值 結果:481842
三、累加器
Product aggregate1 = products.Aggregate((total, next) =>//累加器,對products中每一個元素執行一次Func { total.Price += next.Price; return total; });
上面的代碼可以做一下優化
decimal aggregate2 = products.Aggregate(2000M, (total, next) =>//累加器可以給初始值,這里給的值是2000 { total += next.Price; return total;//這里返回的類型和初始值一致 });
累加器操作的時候盡量用值類型,上面2段代碼如果一起執行,aggregate2的值就會出現異常。
四、SELECT
string[] select1 = products.Select(p => p.Name).ToArray();//選擇單列,可以轉換成數組 var select2 = products.Select(p => new { p.ID, p.Name }).ToDictionary(d => d.ID);//選擇兩列,可以轉換成鍵值對 var selectMore = products.Select(p => new { p.ID, p.Name, p.Price }).ToList();//選擇多列,可以轉換成對象 //鍵值對必須要保證鍵值是唯一的,在鍵值不唯一的情況可以使用ToLookup方法 var lookup = products.ToLookup(l => l.IsFavorite, p => new { p.ID, p.Name, p.Region, p.Price }).ToList(); lookup.ForEach(l => { Console.WriteLine(l.Key ? "已收藏" : "未收藏"); l.ToList().ForEach(item => Console.WriteLine("\t{0}\t{1}\t{2}\t{3}", item.ID, item.Name, item.Region, item.Price)); });
五、ORDER BY
var rightOrder = products.OrderBy(p => p.IsFavorite).ThenByDescending(p => p.ID).ToList();//主IsFavorite,次ID var errorOrder = products.OrderBy(p => p.IsFavorite).OrderByDescending(p => p.ID).ToList();//主ID,次IsFavorite
六、GROUP BY
var group = products.GroupBy(p => p.IsFavorite).Select(g => new { IsFavorite = g.Key, SumPrice = g.Sum(item => item.Price), CountItem = g.Count() }).ToList();
當然在寫拉姆達表達式的時候,也順便說一個LINQ的用法
var groupLinq = (from p in products group p by p.IsFavorite into g select new { IsFavorite = g.Key, SumPrice = g.Sum(item => item.Price), CountItem = g.Count() }).ToList();
七、WHERE
List<Product> distinct = products.Distinct().ToList();//去掉重復的記錄 List<Product> take = products.Take(3).ToList();//順序取3條記錄 List<Product> takeWhile = products.TakeWhile(p => p.ID <= 4).ToList();//只要不滿足條件了,返回所有當前記錄 List<Product> skip = products.Skip(3).ToList();//順序跳過3條記錄 List<Product> skipWhile = products.SkipWhile(p => p.Price < 100000).ToList();//只要不滿足條件了,返回所有剩余記錄 List<Product> contains = products.Where(p => p.Name.Contains("紅")).ToList();//包含“紅”的集合 Product first = products.Where(p => p.Name.StartsWith("大")).First();//“大”開頭的第一條記錄 如果無記錄,直接報異常 Product lastDefault = products.Where(p => p.Name.EndsWith("胡")).LastOrDefault();//“胡”結尾的最后一條記錄 如果無記錄,返回默認值(對象返回null)不會報異常 Product single = products.Where(p => p.ID == 1).SingleOrDefault();//取單條記錄,有多條時會報異常 Product elementDefault = products.ElementAtOrDefault(10);//返回第10條記錄 如果沒有第10條記錄,返回默認值(對象返回null)不會報異常
八、默認
products.DefaultIfEmpty(new Product { ID = 999, Name = "默認產品", Region = "默認地區", Price = 0 });//判斷是否為空,是返回默認值,否返回products
單集合操作講得差不多了,下面說一下多集合操作的,還是老套路,先弄點數據,這里我們數據用最普遍的DataTable格式
DataTable table1 = new DataTable(); table1.Columns.Add("ID"); table1.Columns.Add("Name"); table1.Columns.Add("Amount"); table1.Columns.Add("Description"); table1.Rows.Add("1", "張三", "200", "不知道和張三豐有什么關系?"); table1.Rows.Add("2", "李四", "4", "無"); table1.Rows.Add("3", "王五", "5", "是住你家隔壁的那位嗎?"); DataTable table2 = new DataTable(); table2.Columns.Add("ID"); table2.Columns.Add("Name"); table2.Columns.Add("Amount"); table2.Columns.Add("Description"); table2.Rows.Add("1", "張三", "200", "不知道和張三豐有什么關系?"); table2.Rows.Add("3", "老王", "15000", "這才是隔壁那位吧"); table2.Rows.Add("5", "老劉", "20", "無");
九、JOIN
//兩表內聯,結果有2條記錄 var joinTable = table1.AsEnumerable().Join(table2.AsEnumerable(), left => left["ID"].ToString(), right => right["ID"].ToString(), (left, right) => new { LeftID = left["ID"].ToString(), RightID = right["ID"].ToString(), LeftName = left["Name"].ToString(), RightName = right["Name"].ToString() }).ToList(); joinTable.ForEach(t => Console.WriteLine("{0}\t{1}\t{2}\t{3}", t.LeftID, t.RightID, t.LeftName, t.RightName));
十、GROUPJOIN
//以第一個表為基准,對第二個表進行分組 var groupJoinTable = table1.AsEnumerable().GroupJoin(table2.AsEnumerable(), left => left["Description"].ToString(), right => right["Description"].ToString(), (key, g) => new { Key = key["Description"].ToString(), Count = g.Count(), TotalAmount = g.Where(s => decimal.Parse(s["Amount"].ToString()) > 20).Sum(s => decimal.Parse(s["Amount"].ToString())) }).ToList(); groupJoinTable.ForEach(t => Console.WriteLine("{0}\t{1}\t{2}", t.Key, t.Count, t.TotalAmount));
這里的統計不會包括第一個表的記錄,第一個表只何為一個索引使用
十一、比較兩個表是否相等
bool isEqual = table1.AsEnumerable().Where(t => t["ID"].ToString() == "1") .SequenceEqual(table2.AsEnumerable().Where(t => t["ID"].ToString() == "1"), DataRowComparer.Default); Console.WriteLine(isEqual);
這里只是做了單條記錄的比較,為的只是返回一個TRUE,整個集合比較也是可以的
十二、連接兩個表,不去重復,列取公共部分
var concatTable = table1.AsEnumerable().Concat(table2.AsEnumerable()).ToList(); concatTable.ForEach(t => Console.WriteLine("{0}\t{1}\t{2}\t{3}", t["ID"], t["Name"], t["Amount"], t["Description"]));
十三、差集、交集、並集
//兩表的差集 var exceptTable = table1.AsEnumerable().Except(table2.AsEnumerable(), DataRowComparer.Default).ToList(); exceptTable.ForEach(t => Console.WriteLine("{0}\t{1}\t{2}\t{3}", t["ID"], t["Name"], t["Amount"], t["Description"])); //兩表的交集 var intersectTable = table1.AsEnumerable().Intersect(table2.AsEnumerable(), DataRowComparer.Default).ToList(); intersectTable.ForEach(t => Console.WriteLine("{0}\t{1}\t{2}\t{3}", t["ID"], t["Name"], t["Amount"], t["Description"])); //兩表的並集 var unionTable = table1.AsEnumerable().Union(table2.AsEnumerable(), DataRowComparer.Default).ToList(); unionTable.ForEach(t => Console.WriteLine("{0}\t{1}\t{2}\t{3}", t["ID"], t["Name"], t["Amount"], t["Description"]));
最后說一個比較好玩的方法,還是老規矩,先弄數據
List<Store> stores = new List<Store> { new Store { ID = 1, Name = "城北", Products = new List<Product> { new Product { ID=1, Name="路易十八比薩餅", Region="意大利", Price=79961, IsFavorite = false }, new Product { ID=2, Name="澳洲胡桃", Region="澳洲", Price=195, IsFavorite = false }, new Product { ID=3, Name="Almas魚子醬", Region="伊朗", Price=129950, IsFavorite = false } } }, new Store { ID = 1, Name = "城南", Products = new List<Product> { new Product { ID=4, Name="和牛肉", Region="日本", Price=3250, IsFavorite = true }, new Product { ID=5, Name="麝香貓咖啡豆", Region="印尼", Price=2000, IsFavorite = true }, new Product { ID=6, Name="大紅袍茶葉", Region="中國", Price=208000, IsFavorite = true } } }, new Store { ID = 1, Name = "城東", Products = new List<Product> { new Product { ID=7, Name="Kona Nigari礦泉水", Region="美國", Price=13000, IsFavorite = true }, new Product { ID=8, Name="Diva伏特加", Region="北歐", Price=6500, IsFavorite = false }, new Product { ID=9, Name="番紅花的雄蕊", Region="地中海", Price=38986, IsFavorite = false } } } };
我把上面的9個產品分到了3個倉庫里面存在,當我要查找金額小於10000的所有產品時,按以前的做法就要寫2個FOREACH循環,現在用到SELECTMANY就方便多了
var selectMany = stores.SelectMany(s => s.Products).Where(p => p.Price < 10000).ToList(); selectMany.ForEach(item => Console.WriteLine("\t{0}\t{1}\t{2}\t{3}", item.ID, item.Name, item.Region, item.Price));
當然,也可以用LINQ的方式
var linqSelectMany = from s in stores from p in s.Products where p.Price < 10000 select p; linqSelectMany.ToList().ForEach(item => Console.WriteLine("\t{0}\t{1}\t{2}\t{3}", item.ID, item.Name, item.Region, item.Price));