VB.NET List 筆記 (精進篇)
在 VB.NET 的世界裡,List(Of T) 就像一個「彈性儲物櫃」陣列是固定大小的櫃子,而 List 像是可以隨時增減格子的彈性儲物櫃,想放多少就放多少。。與傳統陣列不同,List(Of T) 能夠動態調整大小,讓您在不知道確切資料量的情況下,輕鬆管理資料集合。它提供了豐富的方法來新增、刪除、搜尋和排序元素,是現代 VB.NET 開發中處理集合資料的首選工具。無論是管理學生名單、產品清單,還是處理即時資料流,List(Of T) 都能讓您的程式碼更簡潔、更有效率。
認識 List(Of T)
List(Of T): List(Of T) 是 .NET Framework 提供的泛型集合類別泛型表示 T 可以是任何型別,如 Integer、String 或自訂類別,讓 List 具有型別安全性。。它儲存在 System.Collections.Generic 命名空間中,提供了動態陣列的功能。與固定大小的陣列相比,List(Of T) 可以在執行時期自動擴充或縮減,並提供豐富的方法來操作集合元素。T 代表型別參數例如 List(Of String) 表示儲存字串的清單,List(Of Integer) 表示儲存整數的清單。,定義了清單中儲存的資料型別。
List(Of T) 的主要特性包括:
- 動態大小: 可以在執行時期自動調整容量,無需事先宣告固定大小。
- 型別安全: 透過泛型機制,確保集合中只能儲存指定型別的元素,避免型別轉換錯誤。
- 索引存取: 支援透過索引 (從 0 開始) 快速存取特定位置的元素。
- 豐富的方法: 提供新增、刪除、搜尋、排序等多種操作方法,簡化集合管理。
- 效能優異: 內部使用陣列實作,提供快速的隨機存取和較好的記憶體效率。
理解 List(Of T) 的運作原理,是掌握 VB.NET 集合處理的關鍵第一步。
基礎操作
掌握 List(Of T) 的基本操作是運用它的基礎。以下將介紹最常用的新增、刪除和存取方法。
功能一:新增元素 (Add 與 AddRange)
Add 方法用於在清單末端新增單一元素,而 AddRange 則可以一次新增多個元素。這是建立和擴充清單最基本的操作。
使用的控制項:
- TextBox1:用於輸入要新增的水果名稱。
- Button1:用於新增單一水果到清單。
- Button2:用於一次新增多個水果到清單。
- Button3:用於顯示清單中所有水果。
- Label1:用於顯示清單內容和狀態訊息。
範例程式碼
' 宣告一個儲存字串的 List
Private fruitList As New List(Of String)
' 表單載入時的初始化
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' 設定 Label1 的初始文字
Label1.Text = "水果清單:尚無資料"
' 設定 TextBox1 的提示文字
TextBox1.Text = ""
End Sub
' 按下 Button1 時新增單一水果
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
' 取得使用者輸入的水果名稱
Dim fruitName As String = TextBox1.Text.Trim()
' 檢查輸入是否為空
If String.IsNullOrEmpty(fruitName) Then
' 輸入為空時顯示提示訊息
Label1.Text = "請輸入水果名稱"
' 結束方法執行
Return
End If
' 使用 Add 方法將水果新增到清單末端
fruitList.Add(fruitName)
' 顯示成功訊息
Label1.Text = "已新增:" & fruitName & " (共 " & fruitList.Count & " 項)"
' 清空輸入框
TextBox1.Clear()
End Sub
' 按下 Button2 時一次新增多個水果
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
' 建立一個包含多個水果的陣列
Dim newFruits() As String = {"蘋果", "香蕉", "橘子", "葡萄"}
' 使用 AddRange 方法一次新增多個元素
fruitList.AddRange(newFruits)
' 顯示成功訊息
Label1.Text = "已批次新增 " & newFruits.Length & " 項水果 (共 " & fruitList.Count & " 項)"
End Sub
' 按下 Button3 時顯示所有水果
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
' 檢查清單是否為空
If fruitList.Count = 0 Then
' 清單為空時顯示提示訊息
Label1.Text = "水果清單:尚無資料"
' 結束方法執行
Return
End If
' 建立字串來儲存所有水果名稱
Dim result As String = "水果清單:" & vbCrLf
' 使用 For Each 迴圈遍歷清單中的每個元素
For Each fruit As String In fruitList
' 將每個水果名稱加入結果字串
result &= "• " & fruit & vbCrLf
Next
' 顯示完整的水果清單
Label1.Text = result
End Sub
詳細講解
此範例展示了 List(Of T) 最基本的新增操作。Add 方法將元素加入清單末端,每次呼叫只能新增一個元素。程式首先檢查輸入是否有效,然後使用 fruitList.Add(fruitName) 將水果名稱新增到清單。
AddRange 方法則接受一個集合 (陣列、List 或其他實作 IEnumerable 的類型),一次性將所有元素新增到清單末端。這在需要批次新增資料時非常有用,效能也比多次呼叫 Add 來得好。
透過 Count 屬性可以隨時取得清單中元素的數量。使用 For Each 迴圈可以輕鬆遍歷清單中的所有元素,這是處理集合資料最常用的方式。
功能二:刪除元素 (Remove、RemoveAt 與 Clear)
List 提供多種刪除元素的方法:Remove 用於刪除指定值的元素,RemoveAt 用於刪除指定索引位置的元素,Clear 則清空整個清單。
使用的控制項:
- TextBox1:用於輸入要刪除的水果名稱或索引位置。
- Button1:用於根據名稱刪除水果。
- Button2:用於根據索引位置刪除水果。
- Button3:用於清空整個清單。
- Button4:用於顯示目前清單內容。
- Label1:用於顯示清單內容和操作結果。
範例程式碼
' 宣告一個儲存字串的 List
Private fruitList As New List(Of String)
' 表單載入時的初始化
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' 預先建立一些測試資料
fruitList.AddRange({"蘋果", "香蕉", "橘子", "葡萄", "芒果", "西瓜"})
' 設定 Label1 的初始文字
Label1.Text = "初始清單:蘋果、香蕉、橘子、葡萄、芒果、西瓜"
End Sub
' 按下 Button1 時根據名稱刪除水果
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
' 取得使用者輸入的水果名稱
Dim fruitName As String = TextBox1.Text.Trim()
' 檢查輸入是否為空
If String.IsNullOrEmpty(fruitName) Then
' 輸入為空時顯示提示訊息
Label1.Text = "請輸入要刪除的水果名稱"
' 結束方法執行
Return
End If
' 使用 Remove 方法刪除指定名稱的水果 (只刪除第一個找到的)
Dim removed As Boolean = fruitList.Remove(fruitName)
' 檢查是否成功刪除
If removed Then
' 刪除成功時顯示訊息
Label1.Text = "已刪除:" & fruitName & " (剩餘 " & fruitList.Count & " 項)"
Else
' 找不到該水果時顯示訊息
Label1.Text = "找不到水果:" & fruitName
End If
' 清空輸入框
TextBox1.Clear()
End Sub
' 按下 Button2 時根據索引位置刪除水果
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
' 宣告變數儲存索引位置
Dim index As Integer = 0
' 嘗試將輸入轉換為整數
If Not Integer.TryParse(TextBox1.Text, index) Then
' 轉換失敗時顯示錯誤訊息
Label1.Text = "請輸入有效的索引位置 (數字)"
' 結束方法執行
Return
End If
' 檢查索引是否在有效範圍內 (0 到 Count-1)
If index < 0 OrElse index >= fruitList.Count Then
' 索引超出範圍時顯示錯誤訊息
Label1.Text = "索引超出範圍,請輸入 0 到 " & (fruitList.Count - 1) & " 之間的數字"
' 結束方法執行
Return
End If
' 先取得要刪除的水果名稱
Dim fruitName As String = fruitList(index)
' 使用 RemoveAt 方法刪除指定索引位置的元素
fruitList.RemoveAt(index)
' 顯示成功訊息
Label1.Text = "已刪除索引 " & index & " 的水果:" & fruitName & " (剩餘 " & fruitList.Count & " 項)"
' 清空輸入框
TextBox1.Clear()
End Sub
' 按下 Button3 時清空整個清單
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
' 使用 Clear 方法移除清單中的所有元素
fruitList.Clear()
' 顯示清空訊息
Label1.Text = "已清空所有水果,目前清單為空"
End Sub
' 按下 Button4 時顯示目前清單內容
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
' 檢查清單是否為空
If fruitList.Count = 0 Then
' 清單為空時顯示訊息
Label1.Text = "水果清單:目前無資料"
' 結束方法執行
Return
End If
' 建立字串來儲存清單內容
Dim result As String = "水果清單 (共 " & fruitList.Count & " 項):" & vbCrLf
' 使用 For 迴圈遍歷清單,同時顯示索引和值
For i As Integer = 0 To fruitList.Count - 1
' 將索引和水果名稱加入結果字串
result &= "[" & i & "] " & fruitList(i) & vbCrLf
Next
' 顯示完整的水果清單
Label1.Text = result
End Sub
詳細講解
此範例展示了 List 的三種刪除方法。Remove 方法接受一個值作為參數,會搜尋清單中第一個相符的元素並刪除,回傳 Boolean 值表示是否成功刪除。如果清單中有多個相同的元素,只會刪除第一個。
RemoveAt 方法接受索引位置作為參數,直接刪除該位置的元素。使用前必須確保索引在有效範圍內 (0 到 Count-1),否則會產生 ArgumentOutOfRangeException索引超出範圍例外,當存取超出集合大小的索引時會發生。 例外。程式中使用 If index < 0 OrElse index >= fruitList.Count 來檢查索引有效性。
Clear 方法最簡單,不需要任何參數,一次移除清單中所有元素,將 Count 重置為 0。這比逐一刪除元素效率更高。
範例中還展示了如何使用索引存取清單元素 fruitList(index),以及如何在迴圈中同時顯示索引和值,這在除錯和使用者介面顯示時非常實用。
進階查找與篩選
List 提供了強大的搜尋和篩選功能,讓您能快速找到符合條件的元素,或篩選出特定的資料子集。
功能三:搜尋元素 (Find、FindAll 與 Exists)
Find 方法尋找符合條件的第一個元素,FindAll 尋找所有符合條件的元素並回傳新的 List,Exists 則檢查是否存在符合條件的元素。
使用的控制項:
- TextBox1:用於輸入搜尋的關鍵字或最低分數。
- Button1:用於尋找第一個包含關鍵字的學生。
- Button2:用於尋找所有包含關鍵字的學生。
- Button3:用於檢查是否存在及格的學生。
- Button4:用於顯示所有學生資料。
- Label1:用於顯示搜尋結果。
範例程式碼
' 定義學生類別來儲存學生資料
Public Class Student
' 學生姓名屬性
Public Property Name As String
' 學生分數屬性
Public Property Score As Integer
' 建構函式,用於建立學生物件
Public Sub New(n As String, s As Integer)
' 設定姓名
Name = n
' 設定分數
Score = s
End Sub
End Class
' 宣告一個儲存 Student 物件的 List
Private studentList As New List(Of Student)
' 表單載入時的初始化
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' 建立測試資料,新增多個學生到清單
studentList.Add(New Student("王小明", 85))
studentList.Add(New Student("李小華", 72))
studentList.Add(New Student("張小美", 91))
studentList.Add(New Student("陳小強", 68))
studentList.Add(New Student("林小婷", 78))
' 設定初始訊息
Label1.Text = "已載入 5 位學生資料"
End Sub
' 按下 Button1 時尋找第一個包含關鍵字的學生
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
' 取得使用者輸入的關鍵字
Dim keyword As String = TextBox1.Text.Trim()
' 檢查輸入是否為空
If String.IsNullOrEmpty(keyword) Then
' 輸入為空時顯示提示
Label1.Text = "請輸入搜尋關鍵字"
' 結束方法執行
Return
End If
' 使用 Find 方法尋找第一個姓名包含關鍵字的學生
Dim foundStudent As Student = studentList.Find(Function(s) s.Name.Contains(keyword))
' 檢查是否找到學生
If foundStudent IsNot Nothing Then
' 找到時顯示學生資訊
Label1.Text = "找到學生:" & foundStudent.Name & ",分數:" & foundStudent.Score
Else
' 未找到時顯示訊息
Label1.Text = "找不到包含「" & keyword & "」的學生"
End If
End Sub
' 按下 Button2 時尋找所有包含關鍵字的學生
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
' 取得使用者輸入的關鍵字
Dim keyword As String = TextBox1.Text.Trim()
' 檢查輸入是否為空
If String.IsNullOrEmpty(keyword) Then
' 輸入為空時顯示提示
Label1.Text = "請輸入搜尋關鍵字"
' 結束方法執行
Return
End If
' 使用 FindAll 方法尋找所有姓名包含關鍵字的學生
Dim foundStudents As List(Of Student) = studentList.FindAll(Function(s) s.Name.Contains(keyword))
' 檢查是否找到學生
If foundStudents.Count > 0 Then
' 建立結果字串
Dim result As String = "找到 " & foundStudents.Count & " 位學生:" & vbCrLf
' 遍歷所有找到的學生
For Each student As Student In foundStudents
' 將學生資訊加入結果
result &= student.Name & " (分數:" & student.Score & ")" & vbCrLf
Next
' 顯示結果
Label1.Text = result
Else
' 未找到時顯示訊息
Label1.Text = "找不到包含「" & keyword & "」的學生"
End If
End Sub
' 按下 Button3 時檢查是否存在及格的學生
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
' 宣告及格分數標準
Dim passingScore As Integer = 60
' 使用 Exists 方法檢查是否存在分數大於等於及格標準的學生
Dim hasPassed As Boolean = studentList.Exists(Function(s) s.Score >= passingScore)
' 檢查結果
If hasPassed Then
' 找出所有及格的學生
Dim passedStudents As List(Of Student) = studentList.FindAll(Function(s) s.Score >= passingScore)
' 顯示及格學生數量
Label1.Text = "有 " & passedStudents.Count & " 位學生及格 (≥" & passingScore & " 分)"
Else
' 沒有學生及格時顯示訊息
Label1.Text = "沒有學生達到及格標準 (" & passingScore & " 分)"
End If
End Sub
' 按下 Button4 時顯示所有學生資料
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
' 檢查清單是否為空
If studentList.Count = 0 Then
' 清單為空時顯示訊息
Label1.Text = "學生清單:目前無資料"
' 結束方法執行
Return
End If
' 建立結果字串
Dim result As String = "學生清單 (共 " & studentList.Count & " 位):" & vbCrLf
' 遍歷所有學生
For Each student As Student In studentList
' 將學生資訊加入結果
result &= student.Name & " - " & student.Score & " 分" & vbCrLf
Next
' 顯示結果
Label1.Text = result
End Sub
詳細講解
此範例首先定義了一個 Student 類別來封裝學生資料,包含姓名和分數兩個屬性。這展示了 List 不僅能儲存基本型別,也能儲存自訂類別物件任何類別的物件都可以儲存在 List 中,讓資料結構更有組織性。。
Find 方法接受一個 Predicate(Of T) 委派,通常使用 Lambda 表達式 Function(s) s.Name.Contains(keyword) 來定義搜尋條件。它回傳第一個符合條件的元素,如果找不到則回傳 Nothing。
FindAll 方法使用相同的語法,但會回傳一個包含所有符合條件元素的新 List。這個新 List 與原 List 是獨立的,修改新 List 不會影響原 List。
Exists 方法同樣接受條件判斷式,但只回傳 Boolean 值,表示是否存在至少一個符合條件的元素。它比 Find 更有效率,因為找到第一個符合項目就會停止搜尋。
這些方法的強大之處在於可以使用任何複雜的條件判斷式,讓資料搜尋變得非常靈活。
功能四:條件篩選與統計 (Where 與 Count)
結合 LINQ 的 Where 方法可以進行更複雜的資料篩選,搭配 Count 可以統計符合條件的元素數量。
使用的控制項:
- TextBox1:用於輸入分數門檻。
- Button1:用於篩選高於門檻的學生。
- Button2:用於統計各分數區間的學生數。
- Button3:用於找出最高分和最低分的學生。
- Label1:用於顯示篩選和統計結果。
範例程式碼
' 使用前面定義的 Student 類別
' 宣告一個儲存 Student 物件的 List
Private studentList As New List(Of Student)
' 表單載入時的初始化
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' 建立測試資料,包含不同分數區間的學生
studentList.Add(New Student("王小明", 95))
studentList.Add(New Student("李小華", 72))
studentList.Add(New Student("張小美", 88))
studentList.Add(New Student("陳小強", 56))
studentList.Add(New Student("林小婷", 81))
studentList.Add(New Student("黃小龍", 43))
studentList.Add(New Student("劉小芳", 90))
studentList.Add(New Student("吳小軍", 67))
' 設定初始訊息
Label1.Text = "已載入 8 位學生資料"
End Sub
' 按下 Button1 時篩選分數高於門檻的學生
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
' 宣告變數儲存門檻分數
Dim threshold As Integer = 0
' 嘗試將輸入轉換為整數
If Not Integer.TryParse(TextBox1.Text, threshold) Then
' 轉換失敗時顯示錯誤訊息
Label1.Text = "請輸入有效的分數 (數字)"
' 結束方法執行
Return
End If
' 使用 Where 方法篩選分數大於門檻的學生,ToList 將結果轉為 List
Dim highScorers As List(Of Student) = studentList.Where(Function(s) s.Score > threshold).ToList()
' 檢查是否有符合條件的學生
If highScorers.Count > 0 Then
' 建立結果字串
Dim result As String = "分數高於 " & threshold & " 的學生 (共 " & highScorers.Count & " 位):" & vbCrLf
' 遍歷所有符合條件的學生
For Each student As Student In highScorers
' 將學生資訊加入結果
result &= student.Name & " - " & student.Score & " 分" & vbCrLf
Next
' 顯示結果
Label1.Text = result
Else
' 沒有符合條件的學生時顯示訊息
Label1.Text = "沒有學生分數高於 " & threshold
End If
End Sub
' 按下 Button2 時統計各分數區間的學生數
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
' 統計不及格學生數 (分數小於 60)
Dim failCount As Integer = studentList.Count(Function(s) s.Score < 60)
' 統計及格學生數 (分數 60-79)
Dim passCount As Integer = studentList.Count(Function(s) s.Score >= 60 AndAlso s.Score < 80)
' 統計優良學生數 (分數 80-89)
Dim goodCount As Integer = studentList.Count(Function(s) s.Score >= 80 AndAlso s.Score < 90)
' 統計優秀學生數 (分數 90 以上)
Dim excellentCount As Integer = studentList.Count(Function(s) s.Score >= 90)
' 建立統計結果字串
Dim result As String = "分數區間統計:" & vbCrLf
result &= "不及格 (<60): " & failCount & " 位" & vbCrLf
result &= "及格 (60-79): " & passCount & " 位" & vbCrLf
result &= "優良 (80-89): " & goodCount & " 位" & vbCrLf
result &= "優秀 (≥90): " & excellentCount & " 位" & vbCrLf
result &= "總人數: " & studentList.Count & " 位"
' 顯示統計結果
Label1.Text = result
End Sub
' 按下 Button3 時找出最高分和最低分的學生
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
' 檢查清單是否為空
If studentList.Count = 0 Then
' 清單為空時顯示訊息
Label1.Text = "學生清單為空"
' 結束方法執行
Return
End If
' 使用 Max 方法找出最高分 (需搭配 Lambda 指定比較的屬性)
Dim maxScore As Integer = studentList.Max(Function(s) s.Score)
' 使用 Min 方法找出最低分
Dim minScore As Integer = studentList.Min(Function(s) s.Score)
' 找出所有最高分的學生 (可能有多位同分)
Dim topStudents As List(Of Student) = studentList.Where(Function(s) s.Score = maxScore).ToList()
' 找出所有最低分的學生
Dim bottomStudents As List(Of Student) = studentList.Where(Function(s) s.Score = minScore).ToList()
' 建立結果字串
Dim result As String = "最高分:" & maxScore & " 分" & vbCrLf
' 列出所有最高分學生
For Each student As Student In topStudents
result &= " • " & student.Name & vbCrLf
Next
result &= vbCrLf & "最低分:" & minScore & " 分" & vbCrLf
' 列出所有最低分學生
For Each student As Student In bottomStudents
result &= " • " & student.Name & vbCrLf
Next
' 顯示結果
Label1.Text = result
End Sub
詳細講解
此範例展示了 LINQ (Language Integrated Query) 與 List 的結合應用。Where 方法是 LINQ 的核心方法之一,用於篩選符合條件的元素。它回傳一個 IEnumerable(Of T),通常會使用 ToList() 將結果轉換為 List。
Count 方法有兩種用法:不帶參數時回傳清單總元素數,帶條件判斷式時回傳符合條件的元素數。這讓統計變得非常簡潔,如 studentList.Count(Function(s) s.Score >= 60) 就能統計及格人數。
Max 和 Min 方法用於找出集合中的最大值和最小值。對於物件集合,需要使用 Lambda 表達式指定要比較的屬性,如 studentList.Max(Function(s) s.Score)。
這個範例展示了如何將多個 LINQ 方法組合使用,先用 Max 找出最高分,再用 Where 篩選出所有該分數的學生。這種鏈式呼叫多個方法連續呼叫,前一個方法的回傳值作為下一個方法的輸入,讓程式碼更簡潔。是 LINQ 的特色,讓程式碼更具可讀性。
排序與轉換
List 提供了便利的排序功能,以及與其他資料結構之間的轉換方法,讓資料處理更加靈活。
功能五:排序 (Sort 與自訂排序)
Sort 方法可以對清單元素進行排序。對於簡單型別會使用預設排序,對於物件則可以提供自訂的比較邏輯。
使用的控制項:
- Button1:用於按姓名升序排序。
- Button2:用於按分數降序排序。
- Button3:用於反轉清單順序。
- Button4:用於還原為原始順序。
- Label1:用於顯示排序後的學生清單。
範例程式碼
' 使用前面定義的 Student 類別
' 宣告一個儲存 Student 物件的 List
Private studentList As New List(Of Student)
' 宣告備份清單,用於還原原始順序
Private originalList As New List(Of Student)
' 表單載入時的初始化
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' 建立測試資料
studentList.Add(New Student("王小明", 85))
studentList.Add(New Student("李小華", 72))
studentList.Add(New Student("張小美", 91))
studentList.Add(New Student("陳小強", 68))
studentList.Add(New Student("林小婷", 78))
' 備份原始順序 (使用 ToList 建立新的獨立清單)
originalList = studentList.ToList()
' 顯示初始清單
ShowList()
End Sub
' 按下 Button1 時按姓名升序排序
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
' 使用 Sort 方法搭配 Lambda 表達式,按姓名排序
studentList.Sort(Function(s1, s2) String.Compare(s1.Name, s2.Name))
' 顯示排序後的清單
ShowList()
' 更新標題訊息
Label1.Text = "按姓名升序排序:" & vbCrLf & Label1.Text
End Sub
' 按下 Button2 時按分數降序排序
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
' 使用 Sort 方法搭配 Lambda 表達式,按分數降序排序
studentList.Sort(Function(s1, s2) s2.Score.CompareTo(s1.Score))
' 顯示排序後的清單
ShowList()
' 更新標題訊息
Label1.Text = "按分數降序排序:" & vbCrLf & Label1.Text
End Sub
' 按下 Button3 時反轉清單順序
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
' 使用 Reverse 方法反轉清單中元素的順序
studentList.Reverse()
' 顯示反轉後的清單
ShowList()
' 更新標題訊息
Label1.Text = "已反轉順序:" & vbCrLf & Label1.Text
End Sub
' 按下 Button4 時還原為原始順序
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
' 清空目前清單
studentList.Clear()
' 從備份清單還原 (使用 AddRange 複製所有元素)
studentList.AddRange(originalList)
' 顯示還原後的清單
ShowList()
' 更新標題訊息
Label1.Text = "已還原原始順序:" & vbCrLf & Label1.Text
End Sub
' 共用方法:顯示學生清單
Private Sub ShowList()
' 檢查清單是否為空
If studentList.Count = 0 Then
' 清單為空時顯示訊息
Label1.Text = "學生清單為空"
' 結束方法執行
Return
End If
' 建立結果字串
Dim result As String = ""
' 宣告變數記錄排名
Dim rank As Integer = 1
' 遍歷所有學生
For Each student As Student In studentList
' 將排名、姓名和分數加入結果
result &= rank & ". " & student.Name & " - " & student.Score & " 分" & vbCrLf
' 排名遞增
rank += 1
Next
' 顯示結果
Label1.Text = result
End Sub
詳細講解
此範例展示了 List 的排序功能。Sort 方法可以接受一個 Comparison(Of T) 委派,使用 Lambda 表達式定義比較邏輯。比較函式接受兩個參數,回傳整數:負數表示第一個元素較小,0 表示相等,正數表示第一個元素較大。
對於字串排序,使用 String.Compare 方法,它會按照字典順序也稱為字母順序,依照字元的 Unicode 值排序,中文則按照筆畫或注音排序。排序。對於降序排序,只需要將兩個參數的順序對調,如 Function(s1, s2) s2.Score.CompareTo(s1.Score)。
Reverse 方法直接反轉清單中元素的順序,不需要任何參數。注意這個方法會直接修改原清單,而不是回傳新清單。
範例中使用 ToList() 方法建立清單的深層複製建立一個新的獨立清單,修改新清單不會影響原清單。,用於備份原始資料。這是保存資料快照的常用技巧。
共用方法 ShowList 展示了如何將重複的程式碼抽取為獨立方法,提高程式碼的可維護性和可讀性。
功能六:轉換與匯出 (ToArray、ToString 與 Join)
List 可以轉換為陣列或其他格式,方便與不同的 API 整合或進行資料匯出。
使用的控制項:
- Button1:用於將 List 轉換為陣列並顯示。
- Button2:用於將學生名單匯出為逗號分隔字串。
- Button3:用於將學生資料匯出為格式化文字。
- Button4:用於統計並顯示摘要資訊。
- Label1:用於顯示轉換和匯出結果。
範例程式碼
' 使用前面定義的 Student 類別
' 宣告一個儲存 Student 物件的 List
Private studentList As New List(Of Student)
' 表單載入時的初始化
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' 建立測試資料
studentList.Add(New Student("王小明", 85))
studentList.Add(New Student("李小華", 72))
studentList.Add(New Student("張小美", 91))
studentList.Add(New Student("陳小強", 68))
studentList.Add(New Student("林小婷", 78))
' 設定初始訊息
Label1.Text = "已載入 5 位學生資料"
End Sub
' 按下 Button1 時將 List 轉換為陣列
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
' 使用 ToArray 方法將 List 轉換為陣列
Dim studentArray() As Student = studentList.ToArray()
' 建立結果字串
Dim result As String = "已轉換為陣列 (長度:" & studentArray.Length & "):" & vbCrLf
' 使用 For 迴圈遍歷陣列
For i As Integer = 0 To studentArray.Length - 1
' 將陣列索引和元素資訊加入結果
result &= "[" & i & "] " & studentArray(i).Name & vbCrLf
Next
' 顯示結果
Label1.Text = result
End Sub
' 按下 Button2 時匯出為逗號分隔字串
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
' 使用 LINQ 的 Select 將每個學生物件轉換為姓名字串
Dim names As IEnumerable(Of String) = studentList.Select(Function(s) s.Name)
' 使用 String.Join 將所有姓名用逗號連接
Dim csvString As String = String.Join(", ", names)
' 建立結果字串
Dim result As String = "學生名單 (CSV 格式):" & vbCrLf
result &= csvString & vbCrLf & vbCrLf
result &= "可複製此格式用於匯出"
' 顯示結果
Label1.Text = result
End Sub
' 按下 Button3 時匯出為格式化文字
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
' 建立標題列
Dim result As String = "學生成績報表" & vbCrLf
result &= String.Repeat("=", 30) & vbCrLf
result &= "姓名" & vbTab & vbTab & "分數" & vbTab & "等第" & vbCrLf
result &= String.Repeat("-", 30) & vbCrLf
' 遍歷所有學生並格式化輸出
For Each student As Student In studentList
' 根據分數判定等第
Dim grade As String = ""
If student.Score >= 90 Then
' 90 分以上為優秀
grade = "優秀"
ElseIf student.Score >= 80 Then
' 80-89 分為優良
grade = "優良"
ElseIf student.Score >= 60 Then
' 60-79 分為及格
grade = "及格"
Else
' 60 分以下為不及格
grade = "不及格"
End If
' 將學生資訊加入結果,使用 Tab 對齊
result &= student.Name & vbTab & vbTab & student.Score & vbTab & grade & vbCrLf
Next
' 加入結尾分隔線
result &= String.Repeat("=", 30)
' 顯示結果
Label1.Text = result
End Sub
' 按下 Button4 時統計並顯示摘要資訊
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
' 檢查清單是否為空
If studentList.Count = 0 Then
' 清單為空時顯示訊息
Label1.Text = "學生清單為空,無法統計"
' 結束方法執行
Return
End If
' 計算總分 (使用 LINQ 的 Sum 方法)
Dim totalScore As Integer = studentList.Sum(Function(s) s.Score)
' 計算平均分數
Dim avgScore As Double = studentList.Average(Function(s) s.Score)
' 找出最高分
Dim maxScore As Integer = studentList.Max(Function(s) s.Score)
' 找出最低分
Dim minScore As Integer = studentList.Min(Function(s) s.Score)
' 計算及格人數
Dim passCount As Integer = studentList.Count(Function(s) s.Score >= 60)
' 計算及格率
Dim passRate As Double = (passCount / studentList.Count) * 100
' 建立摘要報告
Dim result As String = "成績統計摘要" & vbCrLf
result &= String.Repeat("=", 30) & vbCrLf
result &= "總人數: " & studentList.Count & " 位" & vbCrLf
result &= "總分: " & totalScore & " 分" & vbCrLf
result &= "平均分: " & avgScore.ToString("F2") & " 分" & vbCrLf
result &= "最高分: " & maxScore & " 分" & vbCrLf
result &= "最低分: " & minScore & " 分" & vbCrLf
result &= "及格人數:" & passCount & " 位" & vbCrLf
result &= "及格率: " & passRate.ToString("F1") & "%" & vbCrLf
result &= String.Repeat("=", 30)
' 顯示結果
Label1.Text = result
End Sub
詳細講解
此範例展示了 List 與其他資料格式之間的轉換。ToArray() 方法將 List 轉換為同型別的陣列,這在需要呼叫只接受陣列參數的 API 時非常有用。轉換後的陣列是獨立的,修改陣列不會影響原 List。
Select 方法是 LINQ 的投影操作,用於將集合中的每個元素轉換為另一種形式。例如 studentList.Select(Function(s) s.Name) 將 Student 物件集合轉換為姓名字串集合。
String.Join 方法將字串集合用指定的分隔符號連接成單一字串,這是建立 CSV 或其他分隔格式資料的標準方法。
範例中展示了如何建立格式化報表使用對齊、分隔線和條件格式讓資料更易讀,是專業軟體的重要特徵。,包括使用 String.Repeat 建立分隔線,使用 vbTab 對齊欄位,以及使用條件判斷式動態產生內容。
LINQ 的聚合方法如 Sum、Average、Max、Min 等,讓統計運算變得簡潔明瞭。配合 ToString("F2") 等格式化方法,可以精確控制數值的顯示格式。
List 最佳實務建議
建議一:適當的初始容量設定
當您預先知道 List 將包含大量元素時,在建立 List 時指定初始容量可以提升效能。使用 New List(Of T)(capacity) 可以避免多次自動擴充容量時的記憶體重新配置。例如,若您知道將儲存約 1000 個元素,可以使用 Dim list As New List(Of String)(1000)。但對於元素數量不確定或較少的情況,使用預設建構函式即可。
建議二:使用 For Each 而非索引存取
除非需要修改元素或存取索引位置,否則應優先使用 For Each 迴圈遍歷 List。For Each 語法更簡潔、更不容易出錯 (不會發生索引超出範圍),且在某些情況下效能更好。只有在需要同時存取索引和值,或需要向後遍歷時,才使用傳統的 For 迴圈。
建議三:善用 LINQ 簡化程式碼
LINQ 提供了宣告式的資料查詢語法,能大幅簡化集合操作的程式碼。相較於手寫迴圈和條件判斷,LINQ 方法如 Where、Select、OrderBy 等更具可讀性且不易出錯。例如,要找出所有及格學生,studentList.Where(Function(s) s.Score >= 60).ToList() 比手寫迴圈更清晰。但要注意,LINQ 查詢在效能關鍵的場景下可能不如最佳化的迴圈。
注意事項:避免在迴圈中修改集合
在使用 For Each 遍歷 List 時,絕對不要在迴圈內新增或刪除元素,這會導致 InvalidOperationException 例外。如果需要在遍歷時修改集合,應該使用傳統的 For 迴圈並從後往前遍歷 (從 Count-1 到 0),或者先建立一個要刪除元素的清單,遍歷結束後再批次刪除。
注意事項:參考型別的注意事項
List 儲存的若是參考型別 (類別物件),則清單中儲存的是物件的參考參考就像是物件的地址,多個變數可以參考同一個物件。而非物件本身。這意味著,複製 List (如使用 ToList()) 只會複製參考,所有複本仍指向相同的物件。修改物件的屬性會影響所有參考到它的 List。若需要真正的獨立複本,需要實作深層複製建立物件的完整副本,包括其所有屬性和巢狀物件,新舊物件完全獨立。機制。
建議四:考慮使用其他集合型別
List(Of T) 並非萬能,不同的需求應該選擇合適的集合型別。若需要快速查找唯一值,應使用 HashSet(Of T);若需要鍵值對應,應使用 Dictionary(Of TKey, TValue);若需要佇列或堆疊結構,應使用 Queue(Of T) 或 Stack(Of T)。選擇正確的集合型別能大幅提升程式效能和程式碼品質。
| 集合型別 | 適用場景 | 主要特性 |
|---|---|---|
| List(Of T) | 需要索引存取、允許重複元素、需要維持順序的一般集合。 | 動態陣列、支援索引、可重複、有序。 |
| HashSet(Of T) | 需要快速判斷元素是否存在、自動去除重複值。 | 不可重複、無序、極快的查找速度 O(1)。 |
| Dictionary(Of K, V) | 需要透過鍵快速查找對應的值,如查詢表、索引。 | 鍵值對、鍵不可重複、極快的查找速度 O(1)。 |
| LinkedList(Of T) | 頻繁在中間插入或刪除元素,不需要索引存取。 | 雙向鏈結串列、插入/刪除快 O(1)、存取慢 O(n)。 |
| Queue(Of T) | 先進先出 (FIFO) 的場景,如排隊系統、訊息佇列。 | 只能從尾端加入、從前端取出。 |
| Stack(Of T) | 後進先出 (LIFO) 的場景,如復原功能、運算式求值。 | 只能從頂端加入和取出。 |