iT邦幫忙

2025 iThome 鐵人賽

DAY 14
0

前言

集合(Collections)是程式中用來儲存「多筆資料」的結構,從陣列(array)到 List<T>Dictionary<TKey,TValue>HashSet<T>Queue<T>Stack<T>……各種集合各有特性與適合的應用場景。理解常見集合的行為與使用範例是寫出穩定、可維護後端程式的基礎。


常見集合

  • Array(陣列):固定長度、索引存取,效能很好但不方便動態增減。
  • List<T>:最常使用的動態陣列(可增減且支援索引),適合順序資料與常見操作。
  • Dictionary<TKey,TValue>:鍵值對映射(key → value),用於快速查找資料。
  • HashSet<T>:儲存不重複元素、查詢/新增速度快(集合成員唯一)。
  • Queue<T> / Stack<T>:分別代表 FIFO(隊列)與 LIFO(堆疊)行為。

Array(固定長度)

int[] nums = new int[3];
nums[0] = 10;
nums[1] = 20;
nums[2] = 30;
Console.WriteLine(nums[1]); // 輸出 20

List<T>(動態)

List<T> 是開發中最常用的通用集合—可動態增減、支援索引與許多便利方法(Add、Remove、Find 等)。

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<int> list = new List<int>();
        list.Add(10);
        list.Add(20);
        list.Add(30);
        list.Remove(20);
        Console.WriteLine(list[1]); // 輸出 30
    }
}

Dictionary<TKey, TValue>(鍵值對)

Dictionary 在需要以 key 快速查詢時非常合用(例如 id → 物件、設定檔鍵值等)。

using System;
using System.Collections.Generic;

var dict = new Dictionary<string, int>();
dict["apple"] = 3;
dict["banana"] = 5;

if (dict.TryGetValue("apple", out int qty))
{
    Console.WriteLine($"apple: {qty}"); // apple: 3
}

HashSet<T>(不重複集合)

當你只要「存在性檢查」或想確保集合中的元素不重複時,HashSet<T> 是很好的選擇。

var set = new HashSet<int>();
set.Add(1);
set.Add(1); // 重複元素會被忽略
Console.WriteLine(set.Count); // 1

Queue<T> / Stack<T>

// Queue (FIFO)
var q = new Queue<string>();
q.Enqueue("first");
q.Enqueue("second");
Console.WriteLine(q.Dequeue()); // first

// Stack (LIFO)
var s = new Stack<string>();
s.Push("a");
s.Push("b");
Console.WriteLine(s.Pop()); // b

集合提供了一種彈性的方式來處理物件群組,可以依照以下特性來分類不同的集合:

  • 元素存取 (Element access):每個集合都能以列舉方式存取元素,依序逐一訪問。有些集合能透過索引 (index) 存取元素,也就是元素在有序集合中的位置。最常見的範例是System.Collections.Generic.List<T>。其他集合則透過鍵 (key) 來存取元素,元素的值會與單一鍵相關聯。最常見的範例是 System.Collections.Generic.Dictionary<TKey,TValue>。應根據應用程式存取元素的方式,來選擇使用哪一種集合。
  • 效能特性 (Performance profile):每種集合在「新增元素」、「尋找元素」或「刪除元素」等操作上,都有不同的效能表現。可以根據應用程式中最常用的操作,挑選合適的集合類型。
  • 動態增減元素 (Grow and shrink dynamically):大部分集合支援動態新增或移除元素。
    需要注意的是,Array、System.Span<T>System.Memory<T> 不支援動態增減元素。

下面的範例建立並初始化一個字串列表,刪除一個元素,並將一個元素加入列表末尾。每次修改後,它使用 foreach 語句或 for 迴圈遍歷字串:

// Create a list of strings by using a
// collection initializer.
List<string> salmons = ["chinook", "coho", "pink", "sockeye"];

// Iterate through the list.
foreach (var salmon in salmons)
{
    Console.Write(salmon + " ");
}
// Output: chinook coho pink sockeye

// Remove an element from the list by specifying
// the object.
salmons.Remove("coho");


// Iterate using the index:
for (var index = 0; index < salmons.Count; index++)
{
    Console.Write(salmons[index] + " ");
}
// Output: chinook pink sockeye

// Add the removed element
salmons.Add("coho");
// Iterate through the list.
foreach (var salmon in salmons)
{
    Console.Write(salmon + " ");
}
// Output: chinook pink sockeye coho

下面的範例按索引從清單中刪除元素,不是使用 foreach 語句,而是使用降序迭代的 for 語句。 RemoveAt 方法使已刪除元素之後的元素具有較低的索引值:

List<int> numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

// Remove odd numbers.
for (var index = numbers.Count - 1; index >= 0; index--)
{
    if (numbers[index] % 2 == 1)
    {
        // Remove the element by specifying
        // the zero-based index in the list.
        numbers.RemoveAt(index);
    }
}

// Iterate through the list.
// A lambda expression is placed in the ForEach method
// of the List(T) object.
numbers.ForEach(
    number => Console.Write(number + " "));
// Output: 0 2 4 6 8

對於 List<T> 中元素的型別,也可以定義自己的類別。下面的範例中,程式碼中定義了 List<T> 使用的 Galaxy 類別:

private static void IterateThroughList()
{
    var theGalaxies = new List<Galaxy>
    {
        new (){ Name="Tadpole", MegaLightYears=400},
        new (){ Name="Pinwheel", MegaLightYears=25},
        new (){ Name="Milky Way", MegaLightYears=0},
        new (){ Name="Andromeda", MegaLightYears=3}
    };

    foreach (Galaxy theGalaxy in theGalaxies)
    {
        Console.WriteLine(theGalaxy.Name + "  " + theGalaxy.MegaLightYears);
    }

    // Output:
    //  Tadpole  400
    //  Pinwheel  25
    //  Milky Way  0
    //  Andromeda  3
}

public class Galaxy
{
    public string Name { get; set; }
    public int MegaLightYears { get; set; }
}

上一篇
Day13-泛型類別和方法
系列文
30 天從 Python 轉職場 C# 新手入門14
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言