LINQ(筛选)

本文通过示例介绍了如何使用C#中的LINQ进行数据筛选,包括:使用where子句进行条件筛选,结合索引进行更复杂的过滤,利用OfType()进行类型筛选,以及运用复合的from子句和SelectMany()方法对对象成员内的序列进行筛选。通过这些方法,可以实现对数据的深度查询和处理。

下面介绍一些查询的示例,示例应用程序是一个控制台应用程序,使用了如下名称空间:

System

System.Collections.Generic

System.Linq

使用where子句,可以合并多个表达式。例如,找出赢得至少7场比赛的意大利和奥地利赛车手。传递给where子句的表达式的结果类型应是布尔类型:

​
        static void Filtering()
        {
            var racers = from r in Formula1.GetChampions()
                       where r.Wins > 7&& (r.Country == "Italy"|| r.Country =="Austria")
                       select r;

            foreach(var r in racers)
            {
                System.Console.WriteLine($"{r:A}");
            }
        }

​

用这个LINQ查询启动程序,返回的结果如下:

Alberto,Ascari,Italy; starts:32, wins:10
Jochen,Rindt,Austria; starts:60, wins:7

并不是所有的查询都可以用LINQ查询语法完成。也不是所有的扩展方法都映射到LINQ查询子句上。高级查询需要使用扩展方法。为了更好地理解带扩展方法的复杂查询。最好看看简单的查询是如何映射的。使用扩展方法Where()和Select(),会生成与前面LINQ查询非常类似的结果:

        static void FilteringWithMethods()
        {
            var racers = Formula1.GetChampions()
                       .Where(r=>r.Wins >= 7 && (r.Country == "Italy" ||r.Country == "Austria"))
                       .Select(r=>r);
            foreach(var r in racers)
            {
                System.Console.WriteLine($"{r:A}");
            }           

        }

用索引筛选

不能使用LINQ查询的一个例子是Where()方法的重载。在Where()方法的重载中,可以传递第二个参数——索引。索引是筛选器返回的每个结果的计数器。可以在表达式中使用这个索引,执行基于索引的计算。下面的代码由Where()扩展方法调用,它使用索引返回姓氏以A开头、索引为非偶数的赛车手:

        static void FilteringWithIndex()
        {
            var racers = Formula1.GetChampions()
                       .Where((r,index)=>r.LastName.StartsWith("A") && index%2 != 0)
                       ;
            foreach(var r in racers)
            {
                System.Console.WriteLine($"{r:A}");
            }           
        }

结果如下:

Alberto,Ascari,Italy; starts:32, wins:10

类型筛选

为了进行基于类型的筛选,可以使用OfType()扩展方法。这里数组数据包含string和int对象。使用OfType()扩展方法,把string类传送给泛型参数,就从集合中仅返回字符串:

        static void TypeFiltering(){
            object[] data = {"one",2,3,"four","five",6};
            var query = data.OfType<string>();
            foreach(var s in query)
            {
                System.Console.WriteLine(s);
            }
        }

运行这段代码,就会显示字符串one、four和five。

one
four
five

复合的from子句

如果需要根据对象的一个成员进行筛选,而该成员本身是一个系列,就可以使用复合的from子句。Racer类定义了一个属性Cars,其中Cars是一个字符串数组。要筛选驾驶法拉利的所有冠军,可以使用如下所示的LINQ查询。第一个from子句访问从Formula.GetChanpions()方法返回的Racer对象,第二个from子句访问Racer类的Cars属性,以返回所有string类型的赛车手。接着在where子句中使用这些赛车筛选驾驶法拉第的所有冠军。

        static void CompoundFrom()
        {
            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 r in ferrariDrivers)
            {
                System.Console.WriteLine(r);
            }
        } 

C#编辑器把复合的from子句和LINQ查询转换为SelectMany()扩展方法。SelectMany()方法可用于迭代序列的序列。示例中SelectMany()方法的重载版本如下所示:

        public static IEnumerable<TResult> SelectMany<TSource,TCollection,TResult>(
            this IEnumerable<TSource> sources,
            Func<TSource,IEnumerable<TCollection>> collectionSelector,
            Func<TSource,TCollection,TResult> resultSelector);

第一个参数是隐式参数,它从GetChampions()方法中接收Racer对象序列。第二个参数是collectionSelector委托,其中定义了内部序列。在lambda表达式 r=>r.Cars 中,应返回赛车集合。第三个参数是一个委托,现在为每个赛车调用该委托,接收Racer和Car对象。lambda表达式创建了一个匿名类型,它有Racer和Car属性。这个SelectMany()方法的结果示摊平了赛车手和赛车的层次结构,为每辆赛车返回匿名类型的一个新对象集合。

这个新集合传递给Where()方法,筛选出驾驶法拉利的赛车手。最后,调用OrderBy()和Select()方法:

        static void CompundFromWithMethod()
        {
            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);
            foreach(var r in ferrariDrivers)
            {
                System.Console.WriteLine(r);
            }
        }

把SelectMany()泛型方法解析为这里使用的类型,所解析的类型如下所示。在这个例子中,数据源是Racer类型,所筛选的集合是一个string数组,当然所返回的匿名类型的名称是未知的,这里显示为TResult:

        public static IEnumerable<TResult> SelectMany<Racer,string,TResult>(
            this IEnumerable<Racer> sources,
            Func<Racer,IEnumerable<string>> collectionSelector,
            Func<Racer,string,TResult> resultSelector);

因为查询仅从LINQ查询转换为扩展方法,所以结果与前面的相同。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值