【黃忠成】LINQ首部曲: LINQ To Object Part 2 - Using VB.NET(3)
Union
Union函式可以將兩個IEnumerable(Of T)物件整合成一個, 如程式17。
[程式17]
Sub TestUnion()
Dim p1() As Integer = {1, 3, 5, 7, 9, 11}
Dim p2() As Integer = {2, 4, 6, 8, 10, 11}
Dim result = p1.Union(p2)
For Each item In result
Console.WriteLine(item)
Next
Console.ReadLine()
End Sub |
執行結果圖10。
[圖10]
1
3
5
7
9
11
2
4
6
8
10 |
如結果所示,兩個IEnumerable(Of T)物件被整合成一個了,在呼叫Union函式時,我們也可以指定一個實作了IEqualComparaer介面的物件來改變結果,如程式18所示。
[程式18]
Sub TestUnion2()
Dim p1() As String = {"code6421", "tom", "cathy"}
Dim p2() As String = {"code6421", "Tom", "cathy"}
Dim result = p1.Union(p2, _
StringComparer.Create(System.Globalization.CultureInfo.CurrentCulture, True))
For Each item In result
Console.WriteLine(item)
Next
Console.ReadLine()
End Sub |
此例的意思是,以無關大小寫的字串比對方式,比對兩個IEnumerable(Of T)物件中的元素,避免列出重複的元素,圖11是此例的執行結果。
[圖11]
code6421
tom
cathy |
Intersect
Intersect函式可以找出兩個IEnumerable(Of T)物件中相同的元素,如程式19。
[程式19]
Sub TestIntersect()
Dim p1() As Integer = {1, 3, 5, 7, 9, 11}
Dim p2() As Integer = {2, 4, 6, 7, 10, 11}
Dim result = p1.Intersect(p2)
For Each item In result
Console.WriteLine(item)
Next
Console.ReadLine()
End Sub |
此例的執行結果僅會列出相同的數字,也就是7與11。在呼叫Intersect函式時,也可以像Union函式般,指定一個 實作了IEqualComparer介面的物件做為比對基準,如程式20。
[程式20]
Sub TestIntersect2()
Dim p1() As String = {"code6421", "tom", "cathy"}
Dim p2() As String = {"code6421", "Tom", "cathy"}
Dim result = p1.Intersect(p2, _
StringComparer.Create(System.Globalization.CultureInfo.CurrentCulture, True))
For Each item In result
Console.WriteLine(item)
Next
Console.ReadLine()
End Sub |
此例是以無關大小寫字串的方式比對,執行結果圖12。
[圖12]
code6421
tom
cathy |
Tom、tom因字串是以不分大小寫比對的方式,所以僅列出一個。
Except
Except函式允許傳入一個IEnumerable(Of T)物件,以其來比對原始的IEnumerable(Of T)物件中的元素,僅列出未出現在所傳入IEnumerable(Of T)物件中的元素,見程式21。
[程式21]
Sub TestExcept()
Dim p1() As Integer = {1, 3, 5, 7, 9, 11}
Dim p2() As Integer = {2, 4, 6, 8, 10, 11}
Dim result = p1.Except(p2)
For Each item In result
Console.WriteLine(item)
Next
Console.ReadLine()
End Sub |
執行結果如圖13。
[圖13]
1
3
5
7
9 |
如結果所示,11已經被排除了。與Union函式相同,Except函式也允許傳入一個實作了IEqualComparer介面的物件,用來當做比對的基準,如程式22。
[程式22]
Sub TestExcept2()
Dim p1() As String = {"code6421", "tom", "cathy2"}
Dim p2() As String = {"code6421", "Tom", "cathy"}
Dim result = p1.Except(p2, _
StringComparer.Create(System.Globalization.CultureInfo.CurrentCulture, True))
For Each item In result
Console.WriteLine(item)
Next
Console.ReadLine()
End Sub |
此例僅會列出cathy2這個元素。
OfType、Cast
OfType、Cast是LINQ To Object Framework所提供的轉型函式,可以將一個IEnumerable(Of T)物件中的元素轉型為所要求的型別,兩者不同之處在於OfType函式於轉型失敗時並不會丟出例外,而Cast則會丟出例外,見程式23。
[程式23]
Sub TestOfType()
Dim ar As New ArrayList()
ar.Add("Test1")
ar.Add("Test2")
ar.Add("Test3")
ar.Add("Test4")
ar.Add(16)
Dim result = ar.OfType(Of String)()
'Of Type will not raise invalid type-casting exception.
'if you need receive the exception at type-casting,use Cast.
For Each item In result
Console.WriteLine("Type is {0} and value is {1}", item.GetType(), item)
Next
Console.ReadLine()
End Sub |
此例執行結果如圖14。
[圖14]
Type is System.String and value is Test1
Type is System.String and value is Test2
Type is System.String and value is Test3
Type is System.String and value is Test4 |
Sum、Average、Min、Max、Count、
LINQ To Object Framework也提供了Sum、Min、Max、Average、Count等之類常見於SQL指令中的功能函式,Sum用於加總、Min用於取出最小值、Max則用於取出最大值、Count則用於計算符合條件的元素數目,基本上這四個函式的用法大致相同,因此此處我只以Sum函式做為代表例,見程式24。
[程式24]
Sub TestSum()
Dim list() As Integer = {18, 20, 25}
Dim result = list.Sum()
Console.WriteLine(result)
Console.ReadLine()
End Sub |
無意外,此例的執行結果為63,無引數的Sum函式僅作用於數值型別,如Int32、Int64、Decimal、Double、Single等等,當需加總的是一個物件時,就必需傳入一個Lambda Expression來協助Sum函式運算,見程式25。
[程式25]
Sub TestSum2()
Dim persons() = { _
New With {.Name = "code6421", .Age = 18, .Address = "Taipai"}, _
New With {.Name = "jeffray", .Age = 18, .Address = "USA"}, _
New With {.Name = "catch", .Age = 18, .Address = "USA"}, _
New With {.Name = "joe", .Age = 18, .Address = "NY"} _
}
Dim result = persons.Sum(Function(p) p.Age)
Console.WriteLine(result)
Console.ReadLine()
End Sub |
Aggregate
Sum函式用於計算加總值,但若需要的不僅僅是加法呢?例如乘法、減法、除法等等,此時另一個Aggregate函式就能派上用場了,見程式26。
[程式26]
Sub TestAggreate()
Dim list() As Integer = {18, 20, 25}
Dim result = list.Aggregate(Function(x, y) x * y)
Console.WriteLine(result)
Console.ReadLine()
End Sub |
此例的結果是9000,也就是18*20*25後的結果,另外於呼叫Aggregate函式時,也可以指定一個起始值,如程式27。
[程式27]
Sub TestAggreate2()
Dim list() As Integer = {18, 20, 25}
Dim result = list.Aggregate(9000, Function(x, y) x * y)
Console.WriteLine(result)
Console.ReadLine()
End Sub |
此例的結果是,9000*18*20*25 = 81000000。
語法之外,明確使用LINQ TO Object Framework的理由
在本文中的範例,偶而會使用Where函式而不是使用LINQ Expression所提供的where
,讀者或許對此舉會有所疑惑,既然已經有了對應的LINQ Expression,又何必使用函式呼叫呢?簡單的說,LINQ Expression的轉換支援並無法完全取代函式呼叫,以Where例子來說,當使用函式呼叫時,我們可以寫下很複雜的處理函式,如程式28。
[程式28]
Sub TestWhereFunction()
Dim list() As String = {"code6421", "tom", "cathy"}
Dim result = list.Where(AddressOf CompareData)
For Each item In result
Console.WriteLine(item)
Next
Console.ReadLine()
End Sub
Function CompareData(ByVal val As String) As Boolean
Dim conn As New SqlClient.SqlConnection()
'do something of you want..............
Return True
End Function |
這是無法以單純的LINQ Expression來辦到的。
註:C#的Lambda Expression可以允許寫得很複雜,如下:
不過VB.NET 2008並不支援此類寫法,所以還是得走Function模式。 |
Dim、Dim xxx() As Type的差異
一般來說,你可以以Dim來宣告一個陣列,而不事先指定其型別,如下所示:
Dim list() = {1, 2, 3} |
此時當你透過list來呼叫某些LINQ函式時,會發生要求傳入一個Lambda Expression的情況,例如Sum就得寫成下面這樣:
Dim list() = {1, 2, 3}
Dim result = list.Sum(Function(p) p) |
這是因為list陣列被當成Object陣列的緣故,直接於Dim時給予型別,那麼就可以用下面的方式呼叫Sum函式。
Sub Main()
Dim list() As Integer = {1, 2, 3}
Dim result = list.Sum()
Console.WriteLine(result)
Console.ReadLine()
End Sub |
所以,如非必要,使用Dim As Type的方式,可以避免因編譯器的猜測所產生的不必要問題。
還是效能的課題
在LINQ To Object Framework中,效能並非是首要考量的課題,因此許多功能都隱涵效能的問題,例如where,預設是遍覽IEnumerable(Of T)物件中的元素,並一一以傳入的Lambda Expression來驗證,這在某些情況下是不適用的,因為 有時我們只是想尋找某一個符合條件的元素,而且該IEnumerable(Of T)物件是擁有既定排序的,此時採取Binary Search的演演算法來搜尋所要的資料是較有效率的。因此!設計師應該將LINQ To Object Framework視為是一個查詢演演算法的Framework,但其不保證以最快的方式來完成所要求的動作。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-277789/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 【黃忠成】LINQ首部曲: LINQ To Object Part 2 - Using VB.NETObject
- 【黃忠成】LINQ首部曲: LINQ To Object Part 2 - Using VB.NET(2)Object
- LINQ首部曲: LINQ To Object Part 2 - Using VB.NETObject
- LINQ 首部曲 : LINQ To Object Part 1 - Using VB.NET 2008Object
- LINQ系列:Linq to Object投影操作符Object
- LINQ系列:Linq to Object限制操作符Object
- LINQ系列:Linq to Object排序操作符Object排序
- LINQ系列:Linq to Object聚合操作符Object
- LINQ系列:Linq to Object集合操作符Object
- LINQ系列:Linq to Object生成操作符Object
- LINQ系列:Linq to Object元素操作符Object
- LINQ系列:Linq to Object相等操作符Object
- LINQ系列:Linq to Object聯接操作符Object
- LINQ系列:Linq to Object分組操作符Object
- LINQ系列:Linq to Object串聯操作符Object
- LINQ系列:Linq to Object轉換操作符Object
- LINQ系列:Linq to Object量詞操作符Object
- LINQ系列:Linq to Object分割槽操作符Object
- LINQ系列:LINQ to XML操作XML
- LINQ系列:LINQ to XML查詢XML
- LINQ系列:LINQ to SQL Take/SkipSQL
- [譯]LINQ TO SQL 介紹(定義資料模型類) – Part.2SQL模型
- Linq
- LINQ系列:LINQ to DataSet的DataTable操作
- LINQ系列:LINQ to DataSet的DataView操作View
- LINQ系列:LINQ to SQL Where條件SQL
- LINQ系列:LINQ to SQL Concat/UnionSQL
- LINQ系列:LINQ to SQL Join連線SQL
- 使用LINQ Expression構建Que“.NET研究”ry ObjectExpressObject
- LINQ系列:LINQ to SQL Select查詢SQL
- LINQ to SQLSQL
- Lambda、Linq
- LINQ系列:LINQ to SQL Transact-SQL函式SQL函式
- LINQ系列:LINQ to SQL Group by/Having分組SQL
- LINQ系列:C#中與LINQ相關特性C#
- LINQ系列:LINQ to SQL Exists/In/Any/All/ContainsSQLAI
- LINQ to SQL 中可以使用的LINQ函式SQL函式
- linQ基礎