C#使用LINQ查询操作符实例代码

2022-06-06 17:04:49
目录
示例业务背景介绍一、筛选操作符结果:1、索引器筛选2、类型筛选OfType二、投影操作符1、Select 子句结果:相应的lambda表达式:2、复合的From子句三、let子句四、排序操作符使用ThenBy() 和 ThenByDescending() 方法继续排序进行二次排序五、分组操作符1、对嵌套的对象分组2、多字段分组3、分组后再每组里面仅取满足条件的行

示例业务背景介绍

示例参考《C#高级编程(第六版)》LINQ章节(P267>

打开示例代码我们看到:

1、Racer.cs 车手冠军信息类

定义一级方程式世界车手冠军信息。    

2、Team.cs 车队冠军信息类

定义一级方程式世界车队冠军信息。

3、Formula1.cs 一级方程式类

包含两个重要静态方法:(F1是"Formula One"的缩写)

    GetChampions():返回一组车手列表。这个列表包含了1950到2007年之间的所有一级方程式世界车手冠军。GetContructorChampions():返回一组车队列表。这个列表包含了1985到2007年之间的所有一级方程式世界车队冠军。
    [Serializable]
    public class Racer : IComparable<Racer>, IFormattable, IEquatable<Racer>
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int Wins { get; set; }
        public string Country { get; set; }
        public int Starts { get; set; }
        public string[] Cars { get; set; }
        public int[] Years { get; set; }
    
    
        public string ToString(string format, IFormatProvider formatProvider)
        {
            switch (format)
            {
                case null:
                case "N":
                    return ToString();
                case "F":
                    return FirstName;
                case "L":
                    return LastName;
                case "C":
                    return Country;
                case "S":
                    return Starts.ToString();
                case "W":
                    return Wins.ToString();
                case "A":
                    return String.Format("{0} {1}, {2}; starts: {3}, wins: {4}",
                       FirstName, LastName, Country, Starts, Wins);
                default:
                    throw new FormatException(String.Format(
                       "Format {0} not supported", format));
            }
        }
    
        public bool Equals(Racer other)
        {
            return this.FirstName == other.FirstName && this.LastName == other.LastName;
        }
    
    
        public int CompareTo(Racer other)
        {
            return this.LastName.CompareTo(other.LastName);
        }
    
        public string ToString(string format)
        {
            return ToString(format, null);
        }
    
        public override string ToString()
        {
            return String.Format("{0} {1}", FirstName, LastName);
        }
    }
    
    public class Team
    {
        public string Name { get; set; }
        public int[] Years { get; set; }
    }
    
    public class Formula1
    {
        //返回车手冠军列表
        public static List<Racer> GetChampions()
        {
            List<Racer> racers = new List<Racer>(40);
            racers.Add(new Racer() { FirstName = "Nino", LastName = "Farina", Country = "Italy", Starts = 33, Wins = 5, Years = new int[] { 1950 }, Cars = new string[] { "Alfa Romeo" } });
            racers.Add(new Racer() { FirstName = "Alberto", LastName = "Ascari", Country = "Italy", Starts = 32, Wins = 10, Years = new int[] { 1952, 1953 }, Cars = new string[] { "Ferrari" } });
            racers.Add(new Racer() { FirstName = "Juan Manuel", LastName = "Fangio", Country = "Argentina", Starts = 51, Wins = 24, Years = new int[] { 1951, 1954, 1955, 1956, 1957 }, Cars = new string[] { "Alfa Romeo", "Maserati", "Mercedes", "Ferrari" } });
            racers.Add(new Racer() { FirstName = "Mike", LastName = "Hawthorn", Country = "UK", Starts = 45, Wins = 3, Years = new int[] { 1958 }, Cars = new string[] { "Ferrari" } });
            racers.Add(new Racer() { FirstName = "Phil", LastName = "Hill", Country = "USA", Starts = 48, Wins = 3, Years = new int[] { 1961 }, Cars = new string[] { "Ferrari" } });
            racers.Add(new Racer() { FirstName = "John", LastName = "Surtees", Country = "UK", Starts = 111, Wins = 6, Years = new int[] { 1964 }, Cars = new string[] { "Ferrari" } });
            racers.Add(new Racer() { FirstName = "Jim", LastName = "Clark", Country = "UK", Starts = 72, Wins = 25, Years = new int[] { 1963, 1965 }, Cars = new string[] { "Lotus" } });
            racers.Add(new Racer() { FirstName = "Jack", LastName = "Brabham", Country = "Australia", Starts = 125, Wins = 14, Years = new int[] { 1959, 1960, 1966 }, Cars = new string[] { "Cooper", "Brabham" } });
            racers.Add(new Racer() { FirstName = "Denny", LastName = "Hulme", Country = "New Zealand", Starts = 112, Wins = 8, Years = new int[] { 1967 }, Cars = new string[] { "Brabham" } });
            racers.Add(new Racer() { FirstName = "Graham", LastName = "Hill", Country = "UK", Starts = 176, Wins = 14, Years = new int[] { 1962, 1968 }, Cars = new string[] { "BRM", "Lotus" } });
            racers.Add(new Racer() { FirstName = "Jochen", LastName = "Rindt", Country = "Austria", Starts = 60, Wins = 6, Years = new int[] { 1970 }, Cars = new string[] { "Lotus" } });
            racers.Add(new Racer() { FirstName = "Jackie", LastName = "Stewart", Country = "UK", Starts = 99, Wins = 27, Years = new int[] { 1969, 1971, 1973 }, Cars = new string[] { "Matra", "Tyrrell" } });
            racers.Add(new Racer() { FirstName = "Emerson", LastName = "Fittipaldi", Country = "Brazil", Starts = 143, Wins = 14, Years = new int[] { 1972, 1974 }, Cars = new string[] { "Lotus", "McLaren" } });
            racers.Add(new Racer() { FirstName = "James", LastName = "Hunt", Country = "UK", Starts = 91, Wins = 10, Years = new int[] { 1976 }, Cars = new string[] { "McLaren" } });
            racers.Add(new Racer() { FirstName = "Mario", LastName = "Andretti", Country = "USA", Starts = 128, Wins = 12, Years = new int[] { 1978 }, Cars = new string[] { "Lotus" } });
            racers.Add(new Racer() { FirstName = "Jody", LastName = "Scheckter", Country = "South Africa", Starts = 112, Wins = 10, Years = new int[] { 1979 }, Cars = new string[] { "Ferrari" } });
            racers.Add(new Racer() { FirstName = "Alan", LastName = "Jones", Country = "Australia", Starts = 115, Wins = 12, Years = new int[] { 1980 }, Cars = new string[] { "Williams" } });
            racers.Add(new Racer() { FirstName = "Keke", LastName = "Rosberg", Country = "Finland", Starts = 114, Wins = 5, Years = new int[] { 1982 }, Cars = new string[] { "Williams" } });
            racers.Add(new Racer() { FirstName = "Niki", LastName = "Lauda", Country = "Austria", Starts = 173, Wins = 25, Years = new int[] { 1975, 1977, 1984 }, Cars = new string[] { "Ferrari", "McLaren" } });
            racers.Add(new Racer() { FirstName = "Nelson", LastName = "Piquet", Country = "Brazil", Starts = 204, Wins = 23, Years = new int[] { 1981, 1983, 1987 }, Cars = new string[] { "Brabham", "Williams" } });
            racers.Add(new Racer() { FirstName = "Ayrton", LastName = "Senna", Country = "Brazil", Starts = 161, Wins = 41, Years = new int[] { 1988, 1990, 1991 }, Cars = new string[] { "McLaren" } });
            racers.Add(new Racer() { FirstName = "Nigel", LastName = "Mansell", Country = "UK", Starts = 187, Wins = 31, Years = new int[] { 1992 }, Cars = new string[] { "Williams" } });
            racers.Add(new Racer() { FirstName = "Alain", LastName = "Prost", Country = "France", Starts = 197, Wins = 51, Years = new int[] { 1985, 1986, 1989, 1993 }, Cars = new string[] { "McLaren", "Williams" } });
            racers.Add(new Racer() { FirstName = "Damon", LastName = "Hill", Country = "UK", Starts = 114, Wins = 22, Years = new int[] { 1996 }, Cars = new string[] { "Williams" } });
            racers.Add(new Racer() { FirstName = "Jacques", LastName = "Villeneuve", Country = "Canada", Starts = 165, Wins = 11, Years = new int[] { 1997 }, Cars = new string[] { "Williams" } });
            racers.Add(new Racer() { FirstName = "Mika", LastName = "Hakkinen", Country = "Finland", Starts = 160, Wins = 20, Years = new int[] { 1998, 1999 }, Cars = new string[] { "McLaren" } });
            racers.Add(new Racer() { FirstName = "Michael", LastName = "Schumacher", Country = "Germany", Starts = 250, Wins = 91, Years = new int[] { 1994, 1995, 2000, 2001, 2002, 2003, 2004 }, Cars = new string[] { "Benetton", "Ferrari" } });
            racers.Add(new Racer() { FirstName = "Fernando", LastName = "Alonso", Country = "Spain", Starts = 105, Wins = 19, Years = new int[] { 2005, 2006 }, Cars = new string[] { "Renault" } });
            racers.Add(new Racer() { FirstName = "Kimi", LastName = "Räikkönen", Country = "Finland", Starts = 122, Wins = 15, Years = new int[] { 2007 }, Cars = new string[] { "Ferrari" } });
            return racers;
        }
        //返回车队冠军列表
        public static List<Team> GetContructorChampions()
        {
            List<Team> teams = new List<Team>(20);
            teams.Add(new Team() { Name = "Vanwall", Years = new int[] { 1958 } });
            teams.Add(new Team() { Name = "Cooper", Years = new int[] { 1959, 1960 } });
            teams.Add(new Team() { Name = "Ferrari", Years = new int[] { 1961, 1964, 1975, 1976, 1977, 1979, 1982, 1983, 1999, 2000, 2001, 2002, 2003, 2004, 2007 } });
            teams.Add(new Team() { Name = "BRM", Years = new int[] { 1962 } });
            teams.Add(new Team() { Name = "Lotus", Years = new int[] { 1963, 1965, 1968, 1970, 1972, 1973, 1978 } });
            teams.Add(new Team() { Name = "Brabham", Years = new int[] { 1966, 1967 } });
            teams.Add(new Team() { Name = "Matra", Years = new int[] { 1969 } });
            teams.Add(new Team() { Name = "Tyrrell", Years = new int[] { 1971 } });
            teams.Add(new Team() { Name = "McLaren", Years = new int[] { 1974, 1984, 1985, 1988, 1989, 1990, 1991, 1998 } });
            teams.Add(new Team() { Name = "Williams", Years = new int[] { 1980, 1981, 1986, 1987, 1992, 1993, 1994, 1996, 1997 } });
            teams.Add(new Team() { Name = "Benetton", Years = new int[] { 1995 } });
            teams.Add(new Team() { Name = "Renault", Years = new int[] { 2005, 2006 } });
    
            return teams;
        }
    }

    一、筛选操作符

    where子句合并多个表达式。>

    业务说明:找出赢得至少15场比赛的英国和奥地利赛车手。

    var racers = from r in Formula1.GetChampions()
                 where r.Wins > 15 && (r.Country == "Brazil" || r.Country == "Austria")
                 select r;
    
    foreach (var racer in racers)
    {
        Console.WriteLine("{0:A}", racer);
    }

    下面代码有Where扩展方法Where和Select调用。

    var racers = Formula1.GetChampions().
        Where(r => r.Wins > 15 && (r.Country == "Brazil" || r.Country == "Austria")).
        Select(r => r);

    结果:

    //Niki>//Nelson Piquet, Brazil; starts: 204, wins: 23 
    //Ayrton Senna, Brazil; starts: 161, wins: 41

    1、索引器筛选

    索引是筛选器返回的每个结果的计数器。下面由Where扩展方法调用,>

    业务说明:找出上述的、索引为偶数的赛车手

    var racers1 = Formula1.GetChampions()
         .Where((r, index)=> r.Wins > 15 && (r.Country == "Brazil" || r.Country == "Austria") && index % 2 != 0)
         .Select(r => r);

    结果:

    Nelson Piquet

    2、类型筛选OfType

    基于类型筛选,使用>

    业务说明:取出下面所有int类型的参数

    object[] data = { "one", 1, 2, "li" };
    var query = data.OfType<int>();
    
    foreach (var intValue in query)
    {
        Console.WriteLine("{0}", intValue);
    }
    //1
    //2

    例2:取出下面racer类型的值

    IList mixedList = new ArrayList();
    mixedList.Add( Formula1.GetChampions()[0]);
    mixedList.Add(Formula1.GetContructorChampions()[0]);
    mixedList.Add("Two");
    mixedList.Add(3);
    
    var query = mixedList.OfType<Racer>();
    
    foreach (var item in query)
    {
        Console.WriteLine("{0}", item);
    }

    二、投影操作符

    1、Select>

    将序列的每个元素经过lambda表达式处理后投影到一个新类型元素上。

    (与SelectMany不同在于,若单个元素投影到IEnumerable,Select不会对多个IEnumerable进行合并)

    用Select方法创建匿名类型

    var query2 = Formula1.GetChampions()
         .GroupBy(r => r.Country)
         .Select(g => new { Group = g, Count = g.Count() })
         .OrderByDescending(g => g.Count)
         .ThenBy(g => g.Group.Key)
         .Where(g => g.Count > 1)
         .Select(g => new
         {
             Country = g.Group.Key,
             Count = g.Count
         });
    
    foreach (var racer in query2)
    {
        Console.WriteLine("{0:A}", racer);
    }

    结果:

    {>{ Country = Brazil, Count = 3 } 
    { Country = Finland, Count = 3 } 
    { Country = Australia, Count = 2 } 
    { Country = Austria, Count = 2 } 
    { Country = Italy, Count = 2 } 
    { Country = USA, Count = 2 }

    相应的lambda表达式:

    var query3 = from r in Formula1.GetChampions()
                 group r by r.Country into g
                 let count=g.Count()
                 orderby count descending, g.Key
                 where count > 1
                 select new
                 {
                     Country = g.Key,
                     Count = count
    
                 };
    
    foreach (var racer in query3)
    {
        Console.WriteLine("{0:A}", racer);
    }

    2、复合的From子句

    业务说明:筛选驾驶法拉利的所有冠军

    var ferrariDrivers = from r in Formula1.GetChampions()
                         from c in r.Cars
                         where c == "Ferrari"
                         orderby r.LastName
                         select r.FirstName + " " + r.LastName;
    
    foreach (var racer in ferrariDrivers)
    {
        Console.WriteLine("{0:A}", racer);
    }

    结果:

    Alberto Ascari 
    Juan Manuel Fangio 
    Mike Hawthorn 
    Phil Hill 
    Niki Lauda 
    Kimi Räikkönen 
    Jody Scheckter 
    Michael Schumacher 
    John Surtees

    C#编译器会把复合的from语句转换为SelectMany方法。

    var ferrariDrivers = Formula1.GetChampions()
    .SelectMany(r => r.Cars, (r, c) => new { Racer = r, Car = c })
    .Where(r => r.Car == "Ferrari")
    .OrderBy(r => r.Racer.LastName)
    .Select(r => r.Racer.FirstName + " " + r.Racer.LastName);

    符合from子句,将子集合与复集合在同一个表平行展示。

    var ferrariDrivers = Formula1.GetChampions()
    .SelectMany(r => r.Cars, (r, c) => new { Racer = r, Car = c })
    .Where(r => r.Racer.Country == "UK")
    .OrderBy(r => r.Racer.LastName)
    .ThenBy(r => r.Car)
    .Select(r => r);
    
    
    foreach (var racer in ferrariDrivers)
    {
        Console.WriteLine("{0:A}", racer + " :" + racer.Racer.Cars);
    }

    结果:

    { Racer = Jim Clark, Car = Lotus } :Lotus 
    { Racer = Mike Hawthorn, Car = Ferrari } :Ferrari 
    { Racer = Graham Hill, Car = BRM } :BRM 
    { Racer = Graham Hill, Car = Lotus } :BRM 
    { Racer = Damon Hill, Car = Williams } :Williams 
    { Racer = James Hunt, Car = McLaren } :McLaren 
    { Racer = Nigel Mansell, Car = Williams } :Williams 
    { Racer = Jackie Stewart, Car = Matra } :Matra 
    { Racer = Jackie Stewart, Car = Tyrrell } :Matra 
    { Racer = John Surtees, Car = Ferrari } :Ferrari

    三、let子句

    上面的例子:

    var query8 = from r in Formula1.GetChampions()
                 group r by r.Country into g
                 orderby g.Count() descending, g.Key
                 where g.Count() > 1
                 select new
                 {
                     Country = g.Key,
                     Count = g.Count()
                 };

    上面的分组查询Count方法调用了多次。使用let子句可以改变这种形式

    var query10 = from r in Formula1.GetChampions()
                  group r by r.Country into g
                  let count = g.Count()
                  orderby count descending, g.Key
                  where count > 1
                  select new
                  {
                        Country = g.Key,
                        Count = count
                  };

    四、排序操作符

    业务说明:来自英国的赛车手按照赢得比赛的次数进行降序排序

    var query6 = from r in Formula1.GetChampions()
                 where r.Country == "UK"
                 orderby r.Wins descending
                 select r;
    
    foreach (var racer in query6)
    {
        Console.WriteLine("{0:A}", racer);
    }

    结果:

    Nigel Mansell, UK; starts: 187, wins: 31 
    Jackie Stewart, UK; starts: 99, wins: 27 
    Jim Clark, UK; starts: 72, wins: 25 
    Damon Hill, UK; starts: 114, wins: 22 
    Graham Hill, UK; starts: 176, wins: 14 
    James Hunt, UK; starts: 91, wins: 10 
    John Surtees, UK; starts: 111, wins: 6 
    Mike Hawthorn, UK; starts: 45, wins: 3

    使用OrderBy(),OrderByDescending方式替换掉上面的写法:

    var racers2 = Formula1.GetChampions()
        .Where(r => r.Country == "UK")
        .OrderByDescending(r => r.Wins)
        .Select(r => r);

    使用ThenBy()>

    业务说明:获取车手冠军列表,并依次按照Country升序、LastName降序、FirstName升序进行排序。扩展方法 Take 提取前面 10 个元素。

    // 查询表达式
    var racers = (from r in Formula1.GetChampions()
                  orderby r.Country, r.LastName descending, r.FirstName
                  select r).Take(10);
    // 方法语法
    var racers1 = Formula1.GetChampions()
        .OrderBy(r => r.Country)
        .ThenByDescending(r => r.LastName)
        .ThenBy(r => r.FirstName).Take(10); 
    
    foreach (var racer in racers)
    {
        Console.WriteLine("{0:A}", racer);
    }
    //Juan Manuel Fangio, Argentina; starts: 51, wins: 24
    //Alan Jones, Australia; starts: 115, wins: 12
    //Jack Brabham, Australia; starts: 125, wins: 14
    //Jochen Rindt, Austria; starts: 60, wins: 6
    //Niki Lauda, Austria; starts: 173, wins: 25
    //Ayrton Senna, Brazil; starts: 161, wins: 41
    //Nelson Piquet, Brazil; starts: 204, wins: 23
    //Emerson Fittipaldi, Brazil; starts: 143, wins: 14
    //Jacques Villeneuve, Canada; starts: 165, wins: 11
    //Keke Rosberg, Finland; starts: 114, wins: 5

    五、分组操作符

    根据一个关键字值对查询结果进行分组,使用>

    子句 group r by r.Country into g 根据 Country 属性组合。并定义一个新的标识符g,它以后用于访问分组的结果信息。

    业务说明:列出每个国家的冠军数

    var countries = from r in Formula1.GetChampions()
                    group r by r.Country into g
                    orderby g.Count() descending, g.Key
                    where g.Count() > 1
                    select new
                    {
                        Country = g.Key,
                        Count = g.Count()
                    };
    
    foreach (var country in countries)
    {
        Console.WriteLine(format: "{0,-10} {1}", arg0: country.Country, arg1: country.Count);
    }

    结果:

    UK         8 
    Brazil     3 
    Finland    3 
    Australia  2 
    Austria    2 
    Italy      2 
    USA        2

    使用扩展方法,子句 group r by r.Country into g 解析为 GroupBy(r => r.Country) 返回分组序列。

    var countries = Formual.GetChampions()
                .GroupBy(r => r.Country)
                .OrderByDescending(g => g.Count())
                .ThenBy(g => g.Key)
                .Where(g => g.Count() > 1)
                .Select(g => new { Country = g.Key, Count = g.Count() });

    返回值为 IEnumerable。

    1、对嵌套的对象分组

    分组的对象包含嵌套的序列,可以改变>

    业务说明:分组查询每个国家获得冠军的赛车手人数,人数必须大于3,返回国家名称、国家赛车手冠军数量、赛车手名称。

    var query = from r in Formula1.GetChampions()
                group r by r.Country into g
                orderby g.Count() descending, g.Key
                where g.Count() >= 3
                select new
                {
                    Country = g.Key,
                    count = g.Count(),
                    RacerNickName = from r1 in g orderby r1.FirstName select r1.FirstName + " " + r1.LastName
                };
    
    foreach (var g in query)
    {
        Console.WriteLine("{0:A}",g.Country+" "+g.count);
        foreach (var element in  g.RacerNickName)
        {
            Console.WriteLine("---{0:A}",element);
        }
    }

    对应的扩展方法:

    var query1 = Formula1.GetChampions()
        .GroupBy(r => r.Country)
        .OrderByDescending(g => g.Count())
        .ThenBy(g => g.Key)
        .Where(g => g.Count() >= 3)
        .Select(g => new
        {
            Country = g.Key,
            count = g.Count(),
            RacerNickName = g.OrderBy(r1 => r1.FirstName).Select(r1 => r1.FirstName + " " + r1.LastName)
        });

    结果:

    UK 8 
    ---Damon Hill 
    ---Graham Hill 
    ---Jackie Stewart 
    ---James Hunt 
    ---Jim Clark 
    ---John Surtees 
    ---Mike Hawthorn 
    ---Nigel Mansell 
    Brazil 3 
    ---Ayrton Senna 
    ---Emerson Fittipaldi 
    ---Nelson Piquet 
    Finland 3 
    ---Keke Rosberg 
    ---Kimi Räikkönen 
    ---Mika Hakkinen

    2、多字段分组

    var query = from r in Formula1.GetChampions()
                group r by new { r.Country, r.LastName } into g
                orderby g.Count() descending, g.Key.Country, g.Key.LastName
                where g.Count() >= 1
                select new
                {
                    MyGroup = g.Key,
                    count = g.Count(),
                    Racers = g
                };
    
    foreach (var g in query)
    {
        Console.WriteLine("{0:A}", g.MyGroup + " : " + g.count);
        foreach (var element in g.Racers)
        {
            Console.WriteLine("---{0:A}", element);
        }
    }

    结果:

    { Country = UK, LastName = Hill } : 2 
    ---Graham Hill, UK; starts: 176, wins: 14 
    ---Damon Hill, UK; starts: 114, wins: 22 
    { Country = Argentina, LastName = Fangio } : 1 
    ---Juan Manuel Fangio, Argentina; starts: 51, wins: 24

    。。。

    3、分组后再每组里面仅取满足条件的行

    var query = from r in Formula1.GetChampions()
                group r by r.Country into g
                let maxId = g.Max(a => a.Wins)
                orderby g.Key
                where g.Count() >= 1
                from row in g
                where row.Wins == maxId
                select row;
    
    
    foreach (var g in query)
    {
        Console.WriteLine("{0:A}", g);
    }

    到此这篇关于C#使用LINQ查询操作符的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持易采站长站。