第十六节:Linq用法大全(四)

1. OfType

   获取集合中中指定类型元素。

 object[] obj = { 1, 23, 4, 5, 555, "aaa", "bbb" };
 int max = obj.OfType<int>().Max();  //结果是55, 获取int类型中的最大值

2. selectMany

  相当于二次遍历查找,先遍历一级出来item,再遍历二级item. 和Select的区别,Select只遍历一级。

            string[] text = { "Albert was here", "Burke slept late", "Connor is happy" };
            var d1 = text.Select(s => s.Split(' ')).ToList();   //3个元素,每个元素里面又有3个
            var d2 = text.SelectMany(s => s.Split(' ')).ToList();   //9个元素
            var d3 = text.Select(s => s.ToString()).ToList();   //3个元素
            var d4 = text.SelectMany(s => s.ToString()).ToList();   //45个元素,一个字母一个元素,空格也算
            foreach (var item in d4)
            {
                Console.WriteLine(item);
            }

3. GroupJoin

  类似sql中的左连接,linq中join-on-into, 注意:linq中的做外链接操控数据库和直接查出来的集合是不一样,参考集合select的时候要判空,详见下面代码。

代码分享:

 1   List<Person> pList = new List<Person>
 2             {
 3                 new Person{ id = 1, pName = "ABC" },
 4                 new Person{ id = 2, pName = "EFG" },
 5                 new Person{ id = 3, pName = "HIJ"},
 6                 new Person{ id = 4, pName = "KLM"},
 7                 new Person{ id = 5, pName = "NOP" },
 8                 new Person{ id = 6, pName = "QRS"},
 9                 new Person{ id = 7, pName = "TUV"}
10             };
11             List<City> cList = new List<City>
12             {
13                 new City{ id = 1,cName = "Guangzhou",uId=1},
14                 new City{ id = 2,cName = "Shenzhen",uId=2 },
15                 new City{ id = 3,cName = "Beijing" ,uId=3},
16                 new City{ id = 4,cName = "Shanghai",uId=4 },
17                 new City{ id = 8,cName = "K4",uId=4 }
18             };
19             //3.1 先用linq实现一下左连接
20             ////左外连接,需要对右表进行判空 
21             ////此处需要特别注意:这里是对应已经查出来的集合进行左外链接,所以需要对右表进行判空处理,如:cName = k == null ? "" : k.cName
22             ////但是这里如果改成直接操作数据库,pList改为db.Person,cList改为db.City, 则无需对右表进行判空,因为它会生成标准left join的sql语句,操控数据库。
23            Console.WriteLine("------------------------下面是linq左连接查询--------------------------");
24             var result1 = from p in pList
25                           join c in cList on p.id equals c.uId into fk
26                           from k in fk.DefaultIfEmpty()
27                           select new { p.id, p.pName, cName = k == null ? "" : k.cName };
28             var list1 = result1.ToList();
29             foreach (var item in list1)
30             {
31                 Console.WriteLine($"UserId={item.id},Name={item.pName},CityName={item.cName}");
32             }
33             //3.2  重点GroupJoin用法 (等价于上面的左外连接)
34             Console.WriteLine("------------------------下面是GroupJoin左连接查询--------------------------");
35             var result2 = pList.AsQueryable().GroupJoin(cList, p => p.id, c => c.uId, (p, cs) => new
36             {
37                 p.id,
38                 p.pName,
39                 cName = cs.Select(u => u.cName).ToList()
40             });
41             var list2 = result2.ToList();
42             foreach (var item in list2)
43             {
44                 if (item.cName.Count() != 0)
45                 {
46                     foreach (var citem in item.cName)
47                     {
48                         Console.WriteLine($"CityID={item.id},Name={item.pName},CityName={citem}");
49                     }
50                 }
51                 else
52                 {
53                     Console.WriteLine($"CityID={item.id},Name={item.pName},CityName=");
54                 }
55             }

运行结果:

4. ToLookup

  当同一个key要求对应多个value情况ToLookup方法是非常有用的,ToLookup返回一种特殊的数据结构类似我们sql中的group.可以把集合分组并且可以用索引访问这些元素。

注意: Lookup,不像Dictionary, 是不可改变的。 这意味着一旦你创建一个lookup, 你不能对数据源添加或删除元素,即无效,GroupBy后是可以增删的

            var products = new List<Product>
                               {
                                   new Product {pId = "1", Category = "Electronics", Value = 15.0},
                                   new Product {pId = "2", Category = "Groceries", Value = 40.0},
                                   new Product {pId = "3", Category = "Garden", Value = 210.3},
                                   new Product {pId = "4", Category = "Pets", Value = 2.1},
                                   new Product {pId = "5", Category = "Electronics", Value = 19.95},
                                   new Product {pId = "6", Category = "Pets", Value = 21.25},
                                   new Product {pId = "7", Category = "Pets", Value = 5.50},
                                   new Product {pId = "8", Category = "Garden", Value = 13.0},
                                   new Product {pId = "9", Category = "Automotive", Value = 10.0},
                                   new Product {pId = "10", Category = "Electronics", Value = 250.0},
                               };

            {
                Console.WriteLine("使用ToLookup分组");
                var groups = products.ToLookup(p => p.Category);
                //删除所有属于Garden的产品(注意ToLookup删除无效哦)
                products.RemoveAll(p => p.Category == "Garden");
                foreach (var group in groups)
                {
                    Console.WriteLine(group.Key);
                    foreach (var item in group)
                    {
                        Console.WriteLine($"pid={item.pId},Category={item.Category},Value={item.Value}");
                    }
                }
            }
            {
                Console.WriteLine("使用GroupBy分组");
                var groups = products.GroupBy(p => p.Category);
                //删除所有属于Garden的产品
                products.RemoveAll(p => p.Category == "Garden");
                foreach (var group in groups)
                {
                    Console.WriteLine(group.Key);
                    foreach (var item in group)
                    {
                        Console.WriteLine($"pid={item.pId},Category={item.Category},Value={item.Value}");
                    }
                }
            }

运行结果:

5. AsEnumerable/AsQueryable/Cast

(1).AsEnumerable:是延迟执行的,实际上什么都没有发生,当真正使用对象的时候才执行.

(2).AsQueryable:也是延迟执行的,将一个序列向下转换为一个IQueryable, 它生成了一个本地查询的IQueryable包装.

下面看一下各自linq生成的SQL语句:

 

 

(3).Cast:将 IQueryable 的元素转换为指定的类型

            List<object> words = new List<object> { "green", "blue", "violet" };
            var query1 = words.AsQueryable().Cast<string>().ToList();   //将object类型的list集合转换成string的list集合
            //补充写法2
            List<string> query = words.Select(u => (string)u).ToList();  //实际上遍历挨个转换

6. SequenceEqual

  比较list和list之间、数组和数组之间是否相等。

            string[] text1 = { "Albert was here", "Burke slept late", "Connor is happy" };
            string[] text2 = { "Albert was here", "Burke slept late", "Connor is happy" };
            string[] text3 = { "Albert was here", "Burke slept late", "Connor is happy111" };
            string[] text4 = { "Albert was here", "Burke slept late" };
            Console.WriteLine(text1.SequenceEqual(text2));   //true
            Console.WriteLine(text2.SequenceEqual(text3));   //false
            Console.WriteLine(text2.SequenceEqual(text4));   //false

7. DefaultIfEmpty

  返回指定序列的元素;如果序列为空,则返回单一实例集合中的类型参数的默认值。多用于外连接查询。

            int[] arr1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };//构造带元素的数组
            int[] arr2 = { }; //构造一个空数组
            string[] str = { };
            var d1 = arr1.DefaultIfEmpty().ToList();   //9个元素
            var d2 = arr2.DefaultIfEmpty().ToList();   //1个元素,且为0,即int类型的默认值
            var d3 = arr2.DefaultIfEmpty(86).ToList(); //1个元素,且为86,即int类型的默认值
            var d4 = str.DefaultIfEmpty().ToList();    //1个元素,且为null,即string类型的默认值

8. Empty

  内部生成了一个T[]数组,数组的个数为0。

            List<string> list1 = new List<string>();
            var arry2 = Enumerable.Empty<string>();  //Enumerable.Empty<int>() 其实在内部生成了一个T[]数组,数组的个数为0。
            foreach (var item in list1)
            {
                Console.WriteLine(item);
            }
            foreach (var item in arry2)
            {
                Console.WriteLine(item);
            }

9. Range

  生成指定范围内的整数的序列。如下代码:

            var list = Enumerable.Range(10, 100).ToList();  //从10开始,依次添加100个整数,即 10-109
            foreach (var item in list)
            {
                Console.WriteLine(item);
            }

10.Repeat

  包含一个重复值的序列。

            var list = Enumerable.Repeat<int>(10, 100).ToList();   //生成100个10存放在集合中
            foreach (var item in list)
            {
                Console.WriteLine(item);
            }

11.Aggregate

  做一些复杂的聚合运算,例如累计求和,累计求乘积。它接受2个参数,一般第一个参数是称为累积数(默认情况下等于第一个值),而第二个代表了下一个值。第一次计算之后,计算的结果会替换掉第一个参数,继续参与下一次计算,第二个参数往后顺延。

            {
                //11.1 累加和阶乘
                int[] arry1 = { 1, 2, 3, 4, 5 };
                int result1 = arry1.Aggregate((a, b) =>
                {
                    return a + b;
                });
                //执行的操作是: 1+2=3; 3+3=6; 6+4=10; 10+5=15;
                Console.WriteLine($"累加的结果为:{result1}");
                int result2 = arry1.Aggregate((a, b) =>
                {
                    return a * b;
                });
                //执行的操作是: 1*2=2; 2*3=6; 6*4=24; 24*5=120;
                Console.WriteLine($"阶乘的结果为:{result2}");
                //11.2. 实现字符串翻转
                string msg1 = "my name is ypf";
                string[] arry3 = msg1.Split(' ');
                string result3 = arry3.Aggregate((m, n) =>
                {
                    return $"{n} {m}";
                });
                Console.WriteLine($"反转后的结果为:{result3}");
                //11.3 求数组中比“banana”长度长的最长字符串
                string[] fruits = { "apple", "mango", "orange", "passionfruit", "grape" };
                // Determine whether any string in the array is longer than "banana".
                string longestName = fruits.Aggregate("banana", (longest, next) =>
                {
                    return next.Length > longest.Length ? next : longest;
                }, fruit => fruit.ToLower());

                Console.WriteLine("The fruit with the longest name is {0}.", longestName);
            }

运行结果:

 

!

  • 作       者 : Yaopengfei(姚鹏飞)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 声     明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
  • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
 
原文地址:https://www.cnblogs.com/yaopengfei/p/12259731.html