iT邦幫忙

0

【C#學習筆記】16《System.Collections.Generic 常用集合》

  • 分享至 

  • xImage
  •  

上一篇介紹了泛型(Generics)的概念,也簡單帶到了List<T>DictionaryQueueStack
這篇將針對 System.Collections.Generic 中最常用的集合,做更深入的說明與實作範例。


【C#學習筆記】15《泛型(Generics)》


System.Collections.Generic是什麼?

System.Collections.Generic 是 .NET 標準函式庫的一部分。
無論是Unity、ASP.NET、Console App,只要是C#專案都可以使用。

using System.Collections.Generic;

Dictionary< TKey, TValue>

Dictionary<TKey, TValue>是以「Key → Value」配對的集合,適合需要快速查找的情境。
可以把它想成一本字典:透過單字(Key)查到解釋(Value)。

為什麼不用List?

如果用List儲存玩家資料,要找到特定玩家通常需要遍歷整個List

List<string> players = new List<string> { "Alice", "Bob", "Charlie" };
// 要找 Bob,必須一個一個比對

改用Dictionary後,可以直接透過Key取得:

Dictionary<int, string> players = new Dictionary<int, string>();
players.Add(1001, "Alice");
players.Add(1002, "Bob");

Console.WriteLine(players[1002]); // 直接取得 Bob

初始化語法

var inventory = new Dictionary<string, int>
{
    { "Potion", 5 },
    { "Arrow", 100 },
    { "Shield", 1 }
};

[] vs TryGetValue

方式Key不存在時dict[key]拋出KeyNotFoundException,TryGetValue回傳false,不拋例外。
建議優先使用TryGetValue,避免程式因找不到Key而崩潰。

HashSet< T>

HashSet<T>是不允許重複元素的集合,適合需要快速判斷「是否存在」的情境。

基本用法

var set = new HashSet<int>();

set.Add(1);
set.Add(2);
set.Add(2); // 無效,已存在,不會拋例外
set.Add(3);

Console.WriteLine(set.Count);     // 3
Console.WriteLine(set.Contains(2)); // true

set.Remove(1);

集合運算

var setA = new HashSet<int> { 1, 2, 3, 4 };
var setB = new HashSet<int> { 3, 4, 5, 6 };

setA.UnionWith(setB);        // 聯集:{ 1, 2, 3, 4, 5, 6 }
setA.IntersectWith(setB);    // 交集:{ 3, 4 }
setA.ExceptWith(setB);       // 差集(移除與 B 相同的):{ 1, 2 }

setA.IsSubsetOf(setB);       // 是否為子集
setA.Overlaps(setB);         // 是否有交集

UnionWithIntersectWithExceptWith都會修改自身,不會回傳新集合。

遊戲開發情境

// 已解鎖的成就
HashSet<string> unlockedAchievements = new HashSet<string>();
unlockedAchievements.Add("FirstKill");

if (!unlockedAchievements.Contains("FirstKill"))
{
    // 解鎖成就
}

// A* 路徑演算法中已訪問的節點
HashSet<Vector2Int> visited = new HashSet<Vector2Int>();

// 已訪問的地圖格
HashSet<int> exploredTiles = new HashSet<int>();

Queue< T>(先進先出,FIFO)

Queue<T>遵循 先進先出(FIFO) 原則,第一個加入的元素,第一個被取出

基本用法

var queue = new Queue<string>();

queue.Enqueue("Slime");   // 加入末尾
queue.Enqueue("Goblin");
queue.Enqueue("Dragon");

Console.WriteLine(queue.Peek());    // 查看最前面,不取出:Slime
Console.WriteLine(queue.Dequeue()); // 取出最前面並移除:Slime
Console.WriteLine(queue.Count);     // 2

queue.Contains("Goblin"); // true
queue.Clear();

遊戲開發情境

// 怪物生成排程
Queue<string> spawnQueue = new Queue<string>();
spawnQueue.Enqueue("Slime");
spawnQueue.Enqueue("Goblin");

void SpawnNext()
{
    if (spawnQueue.Count > 0)
    {
        string enemy = spawnQueue.Dequeue();
        // 生成怪物...
    }
}

// 技能施放隊列
Queue<string> skillQueue = new Queue<string>();

// NPC 對話佇列
Queue<string> dialogQueue = new Queue<string>();

Stack< T>(後進先出,LIFO)

Stack<T>遵循 後進先出(LIFO) 原則,最後加入的元素,第一個被取出。

基本用法

var stack = new Stack<string>();

stack.Push("Main Menu");  // 加入頂部
stack.Push("Settings");
stack.Push("Audio");

Console.WriteLine(stack.Peek()); // 查看頂部,不取出:Audio
Console.WriteLine(stack.Pop());  // 取出頂部並移除:Audio
Console.WriteLine(stack.Count);  // 2

stack.Contains("Settings"); // true
stack.Clear();

遊戲開發情境

// 場景返回歷史(類似瀏覽器上一頁)
Stack<string> sceneHistory = new Stack<string>();
sceneHistory.Push("MainMenu");
sceneHistory.Push("Lobby");
sceneHistory.Push("GameRoom");

void GoBack()
{
    if (sceneHistory.Count > 0)
    {
        string previousScene = sceneHistory.Pop();
        // 載入上一個場景...
    }
}

// Undo 系統(撤銷操作)
Stack<ICommand> undoStack = new Stack<ICommand>();

void Undo()
{
    if (undoStack.Count > 0)
    {
        undoStack.Pop().Undo();
    }
}

集合選擇指南

需求 推薦集合
有序、可重複、常用索引存取 List<T>
快速 Key → Value 查找 Dictionary<TKey, TValue>
去重、集合運算(聯集/交集) HashSet<T>
排程、任務佇列(先進先出) Queue<T>
撤銷、回溯、場景歷史(後進先出) Stack<T>

總結

System.Collections.Generic 提供了各種不同特性的泛型集合,理解它們各自的適用情境,能讓程式碼更乾淨、效能更好。

  • Dictionary:查找快,適合對應關係
  • HashSet:去重快,適合判斷是否存在
  • Queue:先進先出,適合排程與佇列
  • Stack:後進先出,適合撤銷與歷史記錄

常用API庫

List< T>

list.Add(item)              // 加入末尾
list.AddRange(collection)   // 批次加入
list.Insert(index, item)    // 插入指定位置
list.Remove(item)           // 移除第一個符合
list.RemoveAt(index)        // 移除指定索引
list.RemoveAll(x => x > 5) // 條件移除
list.Clear()                // 清空

list.Contains(item)         // 是否存在
list.Find(x => x > 5)      // 找第一個符合條件的元素
list.FindAll(x => x > 5)   // 找所有符合條件
list.IndexOf(item)          // 取得索引,找不到回傳 -1
list.Exists(x => x > 5)    // 是否存在符合條件的元素

list.Sort()                             // 預設排序
list.Sort((a, b) => a.CompareTo(b))    // 自訂排序
list.Reverse()                          // 反轉
list.Count                              // 元素數量
list.ToArray()                          // 轉成陣列

Dictionary< TKey, TValue>

dict.Add(key, value)                      // 加入(key 重複會例外)
dict[key] = value                         // 加入或覆蓋
dict.Remove(key)                          // 移除
dict.Clear()                              // 清空

dict.ContainsKey(key)                     // 是否有此 key
dict.ContainsValue(value)                 // 是否有此 value
dict.TryGetValue(key, out var val)        // 安全取值(推薦)
dict[key]                                 // 取值(key 不存在會例外)

dict.Count                                // 數量
dict.Keys                                 // 所有 key 集合
dict.Values                               // 所有 value 集合

HashSet< T>

set.Add(item)               // 加入(重複無效)
set.Remove(item)            // 移除
set.Clear()                 // 清空
set.Contains(item)          // 是否存在
set.Count                   // 數量

set.UnionWith(other)        // 聯集(修改自身)
set.IntersectWith(other)    // 交集
set.ExceptWith(other)       // 差集(移除與 other 相同的)
set.IsSubsetOf(other)       // 是否為子集
set.Overlaps(other)         // 是否有交集

Queue< T>

queue.Enqueue(item)         // 加入末尾
queue.Dequeue()             // 取出最前面(移除)
queue.Peek()                // 查看最前面(不移除)
queue.Contains(item)        // 是否存在
queue.Clear()               // 清空
queue.Count                 // 數量

Stack< T>

stack.Push(item)            // 加入頂部
stack.Pop()                 // 取出頂部(移除)
stack.Peek()                // 查看頂部(不移除)
stack.Contains(item)        // 是否存在
stack.Clear()               // 清空
stack.Count                 // 數量

通用模式

// foreach 遍歷(所有集合都支援)
foreach (var item in list) { }
foreach (var kvp in dict) { }

// LINQ 搭配使用(需 using System.Linq)
list.Where(x => x > 5).ToList()
list.OrderBy(x => x).ToList()
list.FirstOrDefault(x => x > 5)
list.Any(x => x > 5)
list.All(x => x > 0)
list.Sum() / list.Max() / list.Min()

圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言