IEnumerable的一些基本方法


在說明用法之后,先要弄點數據。

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));


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM