• 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("	{0}	{1}	{2}	{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}	{1}	{2}	{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}	{1}	{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}	{1}	{2}	{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}	{1}	{2}	{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}	{1}	{2}	{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}	{1}	{2}	{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("	{0}	{1}	{2}	{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("	{0}	{1}	{2}	{3}", item.ID, item.Name, item.Region, item.Price));
  • 相关阅读:
    化DataSet对象并压缩
    数据库连接
    触发器
    事务
    关于C语言的宏
    GCC中的一些参数
    《tkinter实用教程六》tkinter ttk.Label 控件
    《tkinter实用教程三》ttk.Button 控件
    5. 替换空格
    《tkinter实用教程二》ttk 子模块
  • 原文地址:https://www.cnblogs.com/TanSea/p/IEnumerable.html
Copyright © 2020-2023  润新知