C#中Linq的基础操作

前言

LinqC#中提供语言级查询功能和高阶函数 API,以便能够编写具有很高表达力度的声明性代码。使用Linq能够让我们的代码更加简洁。下面先来看一个问题:现在有一个数组,如下所示:

int[] nums = { 8, 1, 9, 4, 3, 6, 7 };

现在我们希望找出这个数组中的偶数,然后将它们降序输出,一般我们会这么写:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] nums = { 8, 1, 9, 4, 3, 6, 7 };

            // 查找偶数
            List<int> list = new List<int>();
            foreach (int num in nums)
            {
                if (num % 2 == 0)
                {
                    list.Add(num);
                }
            }

            // 排序反转
            list.Sort();
            list.Reverse();

            // 输出偶数
            foreach (int num in list)
            {
                Console.WriteLine(num);
            }
            Console.ReadKey();
        }
    }
}

虽然能够实现功能,但这段代码显得有些复杂,这个时候如果使用Linq将会非简单,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] nums = { 8, 1, 9, 4, 3, 6, 7 };
            IEnumerable<int> query = from num in nums
                                     where num % 2 == 0
                                     orderby num descending
                                     select num;
            foreach (int num in query)
            {
                Console.WriteLine(num);
            }
            Console.ReadKey();
        }
    }
}

输出结果如下所示:

8
6
4

1、select

在查询表达式中,select子句可以指定将在执行查询时产生的值的类型。所有的Linq查询语句必须以select或者group结尾。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Student> students = new List<Student>();
            students.Add(new Student() { Id = 1, Name = "张三", Gender = "男", Age = 23 });
            students.Add(new Student() { Id = 2, Name = "李四", Gender = "女", Age = 27 });
            students.Add(new Student() { Id = 3, Name = "王五", Gender = "男", Age = 21 });
            students.Add(new Student() { Id = 4, Name = "赵六", Gender = "女", Age = 25 });

            IEnumerable<Student> query = from student in students
                                         select student;
            foreach (var item in query)
            {
                Console.WriteLine(item.Id + "," + item.Name + "," + item.Gender + "," + item.Age);
            }
            Console.ReadKey();
        }
    }

    class Student
    {
        /// 
        /// 编号
        /// 
        public int Id { get; set; }

        /// 
        /// 姓名
        /// 
        public string Name { get; set; }

        /// 
        /// 性别
        /// 
        public string Gender { get; set; }

        /// 
        /// 年龄
        /// 
        public int Age { get; set; }
    }
}

输出结果如下所示:

1,张三,男,23
2,李四,女,27
3,王五,男,21
4,赵六,女,25

2、where

很多时候我们需要设置查询条件,这时就可以使用where字句。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Student> students = new List<Student>();
            students.Add(new Student() { Id = 1, Name = "张三", Gender = "男", Age = 23 });
            students.Add(new Student() { Id = 2, Name = "李四", Gender = "女", Age = 27 });
            students.Add(new Student() { Id = 3, Name = "王五", Gender = "男", Age = 21 });
            students.Add(new Student() { Id = 4, Name = "赵六", Gender = "女", Age = 25 });

            IEnumerable<Student> query = from student in students
                                         where student.Gender == "男"
                                         select student;
            foreach (var item in query)
            {
                Console.WriteLine(item.Id + "," + item.Name + "," + item.Gender + "," + item.Age);
            }
            Console.ReadKey();
        }
    }

    class Student
    {
        /// 
        /// 编号
        /// 
        public int Id { get; set; }

        /// 
        /// 姓名
        /// 
        public string Name { get; set; }

        /// 
        /// 性别
        /// 
        public string Gender { get; set; }

        /// 
        /// 年龄
        /// 
        public int Age { get; set; }
    }
}

输出结果如下所示:

1,张三,男,23
3,王五,男,21

3、let

let可以创建一个范围变量来存储结果,变量被创建后,不能修改或把其他表达式的结果重新赋值给它。此范围变量可以再后续的Linq中使用。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Student> students = new List<Student>();
            students.Add(new Student() { Id = 1, Name = "张三", Gender = "男", Age = 23 });
            students.Add(new Student() { Id = 2, Name = "李四", Gender = "女", Age = 27 });
            students.Add(new Student() { Id = 3, Name = "王五", Gender = "男", Age = 21 });
            students.Add(new Student() { Id = 4, Name = "赵六", Gender = "女", Age = 25 });

            IEnumerable<Student> query = from student in students
                                         let gender = "男"
                                         let age = 22
                                         where student.Gender == gender && student.Age > age
                                         select student;
            foreach (var item in query)
            {
                Console.WriteLine(item.Id + "," + item.Name + "," + item.Gender + "," + item.Age);
            }
            Console.ReadKey();
        }
    }

    class Student
    {
        /// 
        /// 编号
        /// 
        public int Id { get; set; }

        /// 
        /// 姓名
        /// 
        public string Name { get; set; }

        /// 
        /// 性别
        /// 
        public string Gender { get; set; }

        /// 
        /// 年龄
        /// 
        public int Age { get; set; }
    }
}

输出结果如下所示:

1,张三,男,23

4、orderby

根据字段进行排序也是常见的操作,Linq中可以使用orderby来实现排序。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Student> students = new List<Student>();
            students.Add(new Student() { Id = 1, Name = "张三", Gender = "男", Age = 23 });
            students.Add(new Student() { Id = 2, Name = "李四", Gender = "女", Age = 27 });
            students.Add(new Student() { Id = 3, Name = "王五", Gender = "男", Age = 21 });
            students.Add(new Student() { Id = 4, Name = "赵六", Gender = "女", Age = 25 });

            IEnumerable<Student> query = from student in students
                                         where student.Gender == "男"
                                         orderby student.Age
                                         select student;
            foreach (var item in query)
            {
                Console.WriteLine(item.Id + "," + item.Name + "," + item.Gender + "," + item.Age);
            }
            Console.ReadKey();
        }
    }

    class Student
    {
        /// 
        /// 编号
        /// 
        public int Id { get; set; }

        /// 
        /// 姓名
        /// 
        public string Name { get; set; }

        /// 
        /// 性别
        /// 
        public string Gender { get; set; }

        /// 
        /// 年龄
        /// 
        public int Age { get; set; }
    }
}

输出结果如下所示:

3,王五,男,21
1,张三,男,23

5、group-by

一般使用group-by实现分组查询操作。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Student> students = new List<Student>();
            students.Add(new Student() { Id = 1, Name = "张三", Gender = "男", Age = 23 });
            students.Add(new Student() { Id = 2, Name = "李四", Gender = "女", Age = 27 });
            students.Add(new Student() { Id = 3, Name = "王五", Gender = "男", Age = 21 });
            students.Add(new Student() { Id = 4, Name = "赵六", Gender = "女", Age = 25 });

            IEnumerable<IGrouping<string, Student>> query = from student in students
                                                            group student by student.Gender;
            foreach (var group in query)
            {
                Console.WriteLine(group.Key);
                foreach (var item in group)
                {
                    Console.WriteLine(item.Id + "," + item.Name + "," + item.Gender + "," + item.Age);
                }
            }
            Console.ReadKey();
        }
    }

    class Student
    {
        /// 
        /// 编号
        /// 
        public int Id { get; set; }

        /// 
        /// 姓名
        /// 
        public string Name { get; set; }

        /// 
        /// 性别
        /// 
        public string Gender { get; set; }

        /// 
        /// 年龄
        /// 
        public int Age { get; set; }
    }
}

输出结果如下所示:

男
1,张三,男,23
3,王五,男,21
女
2,李四,女,27
4,赵六,女,25

6、group-by-into

我们也可以使用group-by-into实现分组查询。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Student> students = new List<Student>();
            students.Add(new Student() { Id = 1, Name = "张三", Gender = "男", Age = 23 });
            students.Add(new Student() { Id = 2, Name = "李四", Gender = "女", Age = 27 });
            students.Add(new Student() { Id = 3, Name = "王五", Gender = "男", Age = 21 });
            students.Add(new Student() { Id = 4, Name = "赵六", Gender = "女", Age = 25 });

            IEnumerable<IGrouping<string, Student>> query = from student in students
                                                            group student by student.Gender into groups
                                                            where groups.Key == "男"
                                                            select groups;
            foreach (var group in query)
            {
                foreach (var item in group)
                {
                    Console.WriteLine(item.Id + "," + item.Name + "," + item.Gender + "," + item.Age);
                }
            }
            Console.ReadKey();
        }
    }

    class Student
    {
        /// 
        /// 编号
        /// 
        public int Id { get; set; }

        /// 
        /// 姓名
        /// 
        public string Name { get; set; }

        /// 
        /// 性别
        /// 
        public string Gender { get; set; }

        /// 
        /// 年龄
        /// 
        public int Age { get; set; }
    }
}

输出结果如下所示:

1,张三,男,23
3,王五,男,21

7、内连接查询

内连接查询就是查找两个表中能够匹配的数据,Linq使用join实现内连接查询。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Class> classes = new List<Class>();
            classes.Add(new Class() { Id = 1, ClassName = "一班" });
            classes.Add(new Class() { Id = 2, ClassName = "二班" });
            classes.Add(new Class() { Id = 3, ClassName = "三班" });
            classes.Add(new Class() { Id = 4, ClassName = "四班" });

            List<Student> students = new List<Student>();
            students.Add(new Student() { Id = 1, StudentName = "张三", Gender = "男", Age = 23, ClassId = 1 });
            students.Add(new Student() { Id = 2, StudentName = "李四", Gender = "女", Age = 27, ClassId = 2 });
            students.Add(new Student() { Id = 3, StudentName = "王五", Gender = "男", Age = 21, ClassId = 3 });
            students.Add(new Student() { Id = 4, StudentName = "赵六", Gender = "女", Age = 25, ClassId = 5 });

            IEnumerable<Student> query = from s in students
                                         join c in classes on s.ClassId equals c.Id
                                         select s;
            foreach (var item in query)
            {
                Console.WriteLine(item.Id + "," + item.StudentName + "," + item.Gender + "," + item.Age + "," + item.ClassId);
            }
            Console.ReadKey();
        }
    }

    class Class
    {
        /// 
        /// 编号
        /// 
        public int Id { get; set; }

        /// 
        /// 名称
        /// 
        public string ClassName { get; set; }
    }

    class Student
    {
        /// 
        /// 编号
        /// 
        public int Id { get; set; }

        /// 
        /// 姓名
        /// 
        public string StudentName { get; set; }

        /// 
        /// 性别
        /// 
        public string Gender { get; set; }

        /// 
        /// 年龄
        /// 
        public int Age { get; set; }

        /// 
        /// 班级编号
        /// 
        public int ClassId { get; set; }
    }
}

输出结果如下所示:

1,张三,男,23,1
2,李四,女,27,2
3,王五,男,21,3

8、组连接查询

组连接是与分组查询是一样的。即根据分组得到结果。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Class> classes = new List<Class>();
            classes.Add(new Class() { Id = 1, ClassName = "一班" });
            classes.Add(new Class() { Id = 2, ClassName = "二班" });
            classes.Add(new Class() { Id = 3, ClassName = "三班" });
            classes.Add(new Class() { Id = 4, ClassName = "四班" });

            List<Student> students = new List<Student>();
            students.Add(new Student() { Id = 1, StudentName = "张三", Gender = "男", Age = 23, ClassId = 1 });
            students.Add(new Student() { Id = 2, StudentName = "李四", Gender = "女", Age = 27, ClassId = 2 });
            students.Add(new Student() { Id = 3, StudentName = "王五", Gender = "男", Age = 21, ClassId = 3 });
            students.Add(new Student() { Id = 4, StudentName = "赵六", Gender = "女", Age = 25, ClassId = 4 });

            var query = from c in classes
                        join s in students on c.Id equals s.ClassId into result
                        select new
                        {
                            ClassName = c.ClassName,
                            Students = result
                        };
            foreach (var obj in query)
            {
                Console.WriteLine(obj.ClassName);
                foreach (var item in obj.Students)
                {
                    Console.WriteLine(item.Id + "," + item.StudentName + "," + item.Gender + "," + item.Age);
                }
            }
            Console.ReadKey();
        }
    }

    class Class
    {
        /// 
        /// 编号
        /// 
        public int Id { get; set; }

        /// 
        /// 名称
        /// 
        public string ClassName { get; set; }
    }

    class Student
    {
        /// 
        /// 编号
        /// 
        public int Id { get; set; }

        /// 
        /// 姓名
        /// 
        public string StudentName { get; set; }

        /// 
        /// 性别
        /// 
        public string Gender { get; set; }

        /// 
        /// 年龄
        /// 
        public int Age { get; set; }

        /// 
        /// 班级编号
        /// 
        public int ClassId { get; set; }
    }
}

输出结果如下所示:

一班
1,张三,男,23
二班
2,李四,女,27
三班
3,王五,男,21
四班
4,赵六,女,25

9、左连接查询

使用左连接查询需要注意空值的判断,否则会引发异常。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Class> classes = new List<Class>();
            classes.Add(new Class() { Id = 1, ClassName = "一班" });
            classes.Add(new Class() { Id = 2, ClassName = "二班" });
            classes.Add(new Class() { Id = 3, ClassName = "三班" });
            classes.Add(new Class() { Id = 4, ClassName = "四班" });

            List<Student> students = new List<Student>();
            students.Add(new Student() { Id = 1, StudentName = "张三", Gender = "男", Age = 23, ClassId = 1 });
            students.Add(new Student() { Id = 2, StudentName = "李四", Gender = "女", Age = 27, ClassId = 2 });
            students.Add(new Student() { Id = 3, StudentName = "王五", Gender = "男", Age = 21, ClassId = 3 });
            students.Add(new Student() { Id = 4, StudentName = "赵六", Gender = "女", Age = 25, ClassId = 5 });

            var query = from c in classes
                        join s in students on c.Id equals s.ClassId into result
                        from r in result.DefaultIfEmpty()
                        select new
                        {
                            ClassName = c.ClassName,
                            StudentName = r != null ? r.StudentName : "学生姓名未知",
                            Gender = r != null ? r.Gender : "学生性别未知"
                        };
            foreach (var item in query)
            {
                Console.WriteLine(item.ClassName + "," + item.StudentName);
            }
            Console.ReadKey();
        }
    }

    class Class
    {
        /// 
        /// 编号
        /// 
        public int Id { get; set; }

        /// 
        /// 名称
        /// 
        public string ClassName { get; set; }
    }

    class Student
    {
        /// 
        /// 编号
        /// 
        public int Id { get; set; }

        /// 
        /// 姓名
        /// 
        public string StudentName { get; set; }

        /// 
        /// 性别
        /// 
        public string Gender { get; set; }

        /// 
        /// 年龄
        /// 
        public int Age { get; set; }

        /// 
        /// 班级编号
        /// 
        public int ClassId { get; set; }
    }
}

输出结果如下所示:

一班,张三
二班,李四
三班,王五
四班,学生姓名未知

10、交叉连接

交叉连接很简单,就是两张表的逐一匹配。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Class> classes = new List<Class>();
            classes.Add(new Class() { Id = 1, ClassName = "一班" });
            classes.Add(new Class() { Id = 2, ClassName = "二班" });
            classes.Add(new Class() { Id = 3, ClassName = "三班" });
            classes.Add(new Class() { Id = 4, ClassName = "四班" });

            List<Student> students = new List<Student>();
            students.Add(new Student() { Id = 1, StudentName = "张三", Gender = "男", Age = 23, ClassId = 1 });
            students.Add(new Student() { Id = 2, StudentName = "李四", Gender = "女", Age = 27, ClassId = 2 });
            students.Add(new Student() { Id = 3, StudentName = "王五", Gender = "男", Age = 21, ClassId = 3 });
            students.Add(new Student() { Id = 4, StudentName = "赵六", Gender = "女", Age = 25, ClassId = 5 });

            var query = from s in students
                        from c in classes
                        select new
                        {
                            ClassName = c.ClassName,
                            StudentName = s.StudentName,
                            Gender = s.Gender
                        };
            foreach (var item in query)
            {
                Console.WriteLine(item.ClassName + "," + item.StudentName + "," + item.Gender);
            }
            Console.ReadKey();
        }
    }

    class Class
    {
        /// 
        /// 编号
        /// 
        public int Id { get; set; }

        /// 
        /// 名称
        /// 
        public string ClassName { get; set; }
    }

    class Student
    {
        /// 
        /// 编号
        /// 
        public int Id { get; set; }

        /// 
        /// 姓名
        /// 
        public string StudentName { get; set; }

        /// 
        /// 性别
        /// 
        public string Gender { get; set; }

        /// 
        /// 年龄
        /// 
        public int Age { get; set; }

        /// 
        /// 班级编号
        /// 
        public int ClassId { get; set; }
    }
}

输出结果如下所示:

一班,张三,男
二班,张三,男
三班,张三,男
四班,张三,男
一班,李四,女
二班,李四,女
三班,李四,女
四班,李四,女
一班,王五,男
二班,王五,男
三班,王五,男
四班,王五,男
一班,赵六,女
二班,赵六,女
三班,赵六,女
四班,赵六,女

你可能感兴趣的:(C#)