LINQ Enumerable 续 II
Enumerable.TakeWhile和Enumerable.SkpWhile
Enumerable.TakeWhile和Enumerable.SkpWhile将通过判断条件,来获取和跳过序列。
TakeWhile方法会在条件为真时,将按照条件继续检索序列,直到条件为false。当条件为false时,则立刻停止检索,并返回此时已经检索过的序列。
SkpWhile方法会在条件为真时,将按照条件继续检索序列,直到条件为false。当条件为false时,则立刻停止检索,并返回此时尚未检索的序列。
Dim sw As New StringWriter Dim rnd As New Random Dim cutOff As Integer = rnd.Next(50, 100) 'create a list of containing a fixed set of random numbers: Dim items As New List(Of Integer) For i As Integer = 1 To 20 items.Add(rnd.Next(1, 100)) Next sw.WriteLine("the cutoff value was :{0}", cutOff) sw.WriteLine("the full list is :") For Each item As Integer In items sw.Write("{0},", item) Next Dim list = items.TakeWhile(Function(item) item < cutOff) 'show the list : sw.WriteLine() sw.WriteLine("the result list is (item < cutoff):") For Each item As Integer In list sw.Write("{0},", item) Next 'can also pass in the index to the lambda expression: list = items.TakeWhile(Function(item, index) item > index) sw.WriteLine() sw.WriteLine("result list is (takewhile item >index):") For Each item As Integer In list sw.Write("{0},", item) Next list = items.SkipWhile(Function(item, index) item > index) sw.WriteLine() sw.WriteLine("the result list is (skipwhile item >index):") For Each item As Integer In list sw.Write("{0},", item) Next
输出的一次结果为:
the cutoff value was :62
the full list is :
33,40,60,57,27,98,93,53,31,37,62,91,82,19,64,30,6,74,98,58,
the result list is (item < cutoff):
33,40,60,57,27,
result list is (takewhile item >index):
33,40,60,57,27,98,93,53,31,37,62,91,82,19,64,30,
the result list is (skipwhile item >index):
6,74,98,58,
计算序列
Enumerable类提供了多种不同的序列计算方法。
Enumerable.Average,Enumerable.Count,Enumerable.Sum,Enumerable.Min,Enumerable.Max
不多说了,看代码吧~
Dim db As New SimpleDataContext Dim results = db.Products _ .Where(Function(product) product.CategoryId = 1) _ .Select(Function(product) product.UnitPrice) Dim average = results.Average() Console.WriteLine("average is {0}", average) Dim decimalResults = db.Products _ .Where(Function(product) product.CategoryId = 1) Dim average1 = decimalResults.Average(Function(product) product.UnitPrice) Console.WriteLine("average1 is {0}", average1) Dim average2 = db.Products _ .Where(Function(product) product.CategoryId = 1) _ .Average(Function(product) product.UnitPrice) Console.WriteLine("average2 is {0}", average2) Dim count = results.Count() Console.WriteLine("count is {0}", count) 'calculate filtered count : Dim filteredCount = db.Products.Where(Function(product) product.CategoryId = 1) _ .Count(Function(product) product.ProductName.StartsWith("C")) Console.WriteLine("filteredCount is {0}", filteredCount) 'retrieve the maximum unit price Dim max = db.Products.Where(Function(product) product.CategoryId = 1) _ .Max(Function(product) product.UnitPrice) Console.WriteLine("the Max is {0}", max) 'retrieve the minimum unit price for products 'whose name starts with C Dim min = db.Products.Where(Function(product) product.ProductName.StartsWith("C")) _ .Min(Function(product) product.UnitPrice) Console.WriteLine("the min is {0}", min) 'calculate sum of units in stock: Dim total = db.Products.Where(Function(product) product.CategoryId = 1) _ .Sum(Function(product) product.UnitsInStock) Console.WriteLine("total is {0}", total)
Enumerable.Aggregate
对序列应该累加器。一个很好用的方法~~·
Aggregate方法可简化在值序列上执行计算。此方法的工作原理是对source中的每个元素调用一次func。每次调用func时,Aggregate都将传递序列中的元素和聚合值(聚合值为func的第一个参数)。将seed参数的值作为聚合的初始值。用func的结果替换以前的聚合值。Aggregate返回func的最终结果。
Dim sw As New StringWriter Dim its() As Integer = {4, 8, 8, 3, 9, 0, 7, 8, 2} 'count the even numbers in the array,using a seed value of 0 Dim numEven As Integer = _ its.Aggregate(0, Function(total, number) _ If(number Mod 2 = 0, total + 1, total)) sw.WriteLine("Even Number Count:{0}", numEven) Dim db As New SimpleDataContext Dim customers = db.Customers _ .Where(Function(customer) customer.Country = "France") _ .Select(Function(customer) customer.ContactName) 'note that the seed value is an empty string Dim customerNames = customers.Aggregate(String.Empty, _ Function(current, name) _ If(String.IsNullOrEmpty(current), name, current & "," & name)) 'you can also write like this: Dim customerNames1 = customers.Aggregate(Function(current, name) current & "," & name) sw.WriteLine("France People ") sw.WriteLine(customerNames) sw.WriteLine("Also like this") sw.WriteLine(customerNames1) Dim sentence As String _ = "the quick brown fox jumps over the lazy dog" 'split the string into individual words Dim words() As String = sentence.Split(" "c) 'reverse the word Dim reversed As String = _ words.Aggregate(Function(current, word) word & " " & current) sw.WriteLine("At First the string :") sw.WriteLine(sentence) sw.WriteLine("after reverse:") sw.WriteLine(reversed)
执行集合操作
Enumerable提供了执行集合操作的方法,例如并集和交集的计算
Enumerable.Concat,Enumerable.Union,Enumerable.Intersect,Enumerable.Except
Enumerable.Concat 连接。是将一个序列全部添加到另一个序列。
Enumerable.Unin 合并。是将一个序列连接到另一序列,并从结果中删除重复项。
Enumerable.Intersect 相交。返回的序列是两个输入序列所共有的全部项目。
Enumerable.Except 与非。返回的序列是属于第一个序列但不属于第二个序列全部项目
Dim db As New SimpleDataContext Dim sw As New StringWriter 'create two sequences: Dim groupA = db.Customers _ .Select(Function(customer, index) _ customer.Country).Take(5) Dim groupB = db.Customers _ .Select(Function(customer, index) customer.Country) _ .Skip(30).Take(5) 'show both groups : sw.WriteLine("group1: ") ShowEnumerable(groupA, sw) sw.WriteLine("Group2 :") ShowEnumerable(groupB, sw) 'return the complete list of countries Dim groupForConcat = groupA.Concat(groupB) sw.WriteLine("this is Concat,groupForConcat:") ShowEnumerable(groupForConcat, sw) 'return a unique list of countries in the two groups : Dim gourpForUnique = groupA.Union(groupB) sw.WriteLine("this is Union ,gourpForUnique:") ShowEnumerable(gourpForUnique, sw) Dim groupIntersect = groupA.Intersect(groupB) sw.WriteLine("this is Intersect ,groupIntersect:") ShowEnumerable(groupIntersect, sw) sw.WriteLine("this is Except ,groupExcept:") Dim groupExcept = groupA.Except(groupB) ShowEnumerable(groupExcept, sw)
输出的结果:
group1:
Brazil,Mexico,Mexico,UK,Sweden
Group2 :
Brazil,USA,Venezuela,Brazil,Venezuela
this is Concat,groupForConcat:
Brazil,Mexico,Mexico,UK,Sweden,Brazil,USA,Venezuela,Brazil,Venezuela
this is Union ,gourpForUnique:
Brazil,Mexico,UK,Sweden,USA,Venezuela
this is Intersect ,groupIntersect:
Brazil
this is Except ,groupExcept:
Mexico,UK,Sweden
注意,上面的示例使用的都是默认的简单比较器。如果对复杂对象的序列执行集合操作,可以调用那些接受自定义比较器的重载版本方法。
Enumerable.Join
假设一些场景你提供了两个相关序列,你希望根据这两个序列中的键值关联性将其联接在一起。此类任务会被认为是处理关系型数据库中的某些情况。
Dim db As New SimpleDataContext Dim categrories = db.Categories _ .Where(Function(category) category.CategoryId = 3) Dim results = categrories.Join(db.Products, _ Function(category) category.CategoryId, _ Function(product) product.CategoryId, _ Function(category, product) _ New With {.CategoryName = category.CategoryName, _ .ProductName = product.ProductName}) Dim sw = New StringWriter For Each item In results sw.WriteLine("{0}----{1}", item.CategoryName, item.ProductName) Next
Enumerable.GroupBy
Enumerable.GroupBy方法按照键值将输入序列进行分组,这将创建多组项目。输出序列中的每个组都包含一个”Header”项目以及提供对分组项目访问的Items属性。要调用Enumerable.GroupBy方法,必须至少提供三个函数。第一个提供分组键,第二个提供在组中生成的项目,第三个提供标题内容。
Dim db = New SimpleDataContext Dim groupedProducts = db.Products _ .Where(Function(product) product.UnitsInStock < 10) _ .GroupBy(Function(product) product.CategoryId, _ Function(product) _ New With {product.ProductName, product.UnitsInStock}, _ Function(catId, group) _ New With {.CategoryID = catId, .Count = group.Count(), .Items = group}) Dim sw = New StringWriter For Each grouping In groupedProducts sw.WriteLine("Category {0} :{1} items", grouping.CategoryID, grouping.Count) For Each item In grouping.Items sw.WriteLine("{0} {1} ({2})", vbTab, item.ProductName, item.UnitsInStock) Next Next
输出结果为:
Category 2 :3 items
Chef Anton's Gumbo Mix (0)
Northwoods Cranberry Sauce (6)
Louisiana Hot Spiced Okra (4)
Category 6 :3 items
Alice Mutton (0)
Thüringer Rostbratwurst (0)
Perth Pasties (0)
Category 3 :2 items
Sir Rodney's Scones (3)
Scottish Longbreads (6)
Category 4 :2 items
Gorgonzola Telino (0)
Mascarpone Fabioli (9)
Category 8 :1 items
Røgede sild (5)
Category 7 :1 items
Longlife Tofu (4)