【黃忠成】LINQ首部曲: LINQ To Object Part 2 - Using VB.NET(2)

iDotNetSpace發表於2008-05-19
[程式9]
Sub TestSelectMany()
        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 p2() = { _
                     New With {.Title = "Director"}, _
                     New With {.Title = "Programmer"}, _
                     New With {.Title = "Manager"} _
                    }
 
        Dim result = From s1 In persons _
                     From s2 In p2 _
                     Select New With {.Name = s1.Name, .Title = s2.Title}
 
        For Each item In result
            Console.WriteLine("Name : {0}, Title : {1}", item.Name, item.Title)
        Next
        Console.ReadLine()
    End Sub
此例的執行結果如圖7。
[圖7]
Name : code6421, Title : Director
Name : code6421, Title : Programmer
Name : code6421, Title : Manager
Name : jeffray, Title : Director
Name : jeffray, Title : Programmer
Name : jeffray, Title : Manager
Name : catch, Title : Director
Name : catch, Title : Programmer
Name : catch, Title : Manager
Name : joe, Title : Director
Name : joe, Title : Programmer
Name : joe, Title : Manager
 
Index
 
 LINQ To Object Framework的LINQ Expression允許指定Index,什麼是Index呢 ?請看程式10。
[程式10]
Sub TestIndex()
        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 = From s1 In persons Select s1.Name(0)
        For Each item In result
            Console.WriteLine(item)
        Next
        Console.ReadLine()
    End Sub
此例會列出陣列中Name屬性值的第一個字元,事實上這是當然的結果,因為where後面的語句,會被VB.NET編譯器當成Lambda Expression處理,而Name屬性是string型態,自然也能對其使用()陣列存取子了,同時也因為是string型別,而且會被轉為Lambda Expression,自然能呼叫屬於string型別的Contains函式了。
 
Take、TakeWhile
 
 Take函式可以讓設計師由一個IEnumerable物件中取出指定的元素數量,請見程式11。
[程式11]
Sub TestTake()
        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.Take(2)
        For Each item In result
            Console.WriteLine(item.Name)
        Next
        Console.ReadLine()
    End Sub
此例會從p1中取出前兩個元素,也就是code6421及jeffray,Take函式的功能有點像是SQL Server的Select TOP。另一個TakeWhile函式則可以讓設計師以while的方式來取出IEnumerable中的元素,請見程式12。
[程式12]
Sub TestTakeWhile()
        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.TakeWhile(Function(p) p.Address = "Taipai")
        For Each item In result
            Console.WriteLine(item.Name)
        Next
        Console.ReadLine()
    End Sub
此例的執行結果與Take相同,不同之處在於TakeWhile會一直取出元素,直到某個元素不符合所指定的Lambda Expression為止,這意味著假如指定Address == “USA”時,將不會有任何元素列出,因為陣列中的第一個元素就已經不符合條件了,所以While動作就結束了。
 
Skip、SkipWhile
 
 相對於Take,Skip允許設計師略過指定的元素數,如程式13。
[程式13]
Sub TestSkip()
        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 = (From s1 In persons Select s1).Skip(2)
        For Each item In result
            Console.WriteLine(item.Name)
        Next
        Console.ReadLine()
    End Sub
此例會由catch的元素開始列出。另一個SkipWhile函式與TakeWhile的概念相同,SkipWhile也是以While的觀念執行Skip動作,如程式14。
[程式14]
Sub TestSkipWhile()
        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 = (From s1 In persons Select s1).SkipWhile(Function(p) p.Address = "Taipai")
        For Each item In result
            Console.WriteLine(item.Name)
        Next
        Console.ReadLine()
    End Sub
與TakeWhile一樣,若指定Address == “USA”時,那麼將會列出所有元素,因為在第一個元素時,While就已經結束了。
 
First、FirstOrDefault
 
   First函式允許設計師指定一個Lambda Expression條件式, 她將以此對IEnumerable(Of T)中的元素查詢,並傳回第一個符合條件的元素,當不指定條件式時,First會傳回第一個元素。與Where不同,First只會傳回符合資料的第一個元素,而非內含所有符合條件元素的IEnumerable(Of T)結果集,見程式15。
[程式15]
Sub TestFirst()
        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 = (From s1 In persons Select s1).First()
        Console.WriteLine(result.Name)
        Console.ReadLine()
    End Sub
下例則是使用條件式的寫法。
Sub TestFirst2()
        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 = (From s1 In persons Select s1).First(Function(p) p.Address = "USA")
        Console.WriteLine(result.Name)
        Console.ReadLine()
    End Sub
當IEnumerable(Of T)中未含有符合條件的元素時,First將會引發例外。另一個FirstOrDefault函式與First函式類似,唯一不同之處是當IEnumerable(Of T)中未含有符合條件之元素時,她將回傳元素之型別的預設值(object為null、數值為0)。與First相對的是Last函式,可取得最後一個元素,她也有另一個同型函式為LastOrDefault,設計理念與FirstOrDefault相同。
 
ElementAt、ElementAtOrDefault
 
 ElementAt函式可以取得一個物件集中特定位置的元素,如下所示:
Sub TestElementAt()
        Dim p1() As String = {"code6421", "tom", "cathy"}
        Dim result = p1.ElementAt(1)
        Console.WriteLine(result)
        Console.ReadLine()
End Sub
此例會列出tom這個元素,當指定位置超出物件集大小時,ElementAt會丟擲例外。如同FirstOrDefault一般,ElementAt有另一個同型函式:ElementAtOrDefault,當使用此函式時指定位置超出物件集大小時,不會觸發例外,而是直接回傳預設值(object為null,數值為0)。
 
ToArray、ToList、ToDictionary
 
 這三個函式會將IEnuermable(Of T)轉成Array、List或是Dictionary型別,預設情況下,當我們對某個IEnumerable(Of T)下達Where等條件式時,所取得的結果會是一個IEnumerable(Of T)物件,此時所有條件都尚未執行比對的動作,當對這個IEnumerable(Of T)物件下達MoveNext(For Each會觸發此函式)時,該物件才會進行條件比對。ToArray等函式可以改變此行為模式,當我們對IEnumerable(Of T)物件呼叫這些函式時,其將會以For Each一一巡覽IEnumerable(Of T)物件中的元素並進行條件比對,然後放到另一個結果值後傳回,這也就是說,呼叫此函式所傳回的結果值,將會是已經完成比對後的結果值,操作這個結果集自然比直接操控具條件的結果集來得有效率,程式16是一個使用ToDictionary函式的例子。
[程式16]
Sub TestToDictionary()
        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.ToDictionary(Function(p) p.Name)
        Console.WriteLine(result("code6421").Address)
        Console.ReadLine()
    End Sub
ToDictionary函式為以指定的鍵值為主鍵,將元素轉為Dictionary物件,此時你可透過預設存取子,以主鍵為引數來取得對應之元素。
 
 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-277788/,如需轉載,請註明出處,否則將追究法律責任。

相關文章