zoukankan      html  css  js  c++  java
  • 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));
  • 相关阅读:
    Android开发 ViewConfiguration View的配置信息类
    Android 开发 倒计时功能 转载
    Android 开发 关于7.0 FileUriExposedException异常 详解
    Android 开发 实现文本搜索功能
    Android 开发 Activity里获取View的宽度和高度 转载
    Android 开发 存储目录的详解
    Android 开发 Fresco框架点击小图显示全屏大图实现 ZoomableDraweeView
    Android 开发 将window变暗
    Android 开发 DisplayMetrics获取Android设备的屏幕高宽与其他信息
    Android 开发 DP、PX、SP转换详解
  • 原文地址:https://www.cnblogs.com/TanSea/p/IEnumerable.html
Copyright © 2011-2022 走看看