搜尋是最基礎的資料操作。.NET Array 類別提供豐富的靜態搜尋方法,配合委派、匿名方法、Lambda 演進,程式碼愈發簡潔。本文詳細解析各方法用法與效能特性。
int[] numbers = { 3, 7, 2, 4, 10, 1 };
// 傳統委派寫法
static bool MatchInt(int input) => input == 2;
bool exists = Array.Exists(numbers, new Predicate(MatchInt));
bool exists2 = Array.Exists(numbers, MatchInt); // 方法群組簡寫
// 匿名方法 (C# 2.0)
bool exists3 = Array.Exists(numbers, delegate(int i) { return i == 2; });
// Lambda (C# 3.0+) - 最簡潔
bool exists4 = Array.Exists(numbers, i => i == 2);
IL 碼顯示:匿名方法與 Lambda 編譯結果相同,皆透過委派實作。Lambda 只是語法糖,但更直觀。
int first = Array.Find(numbers, i => i == 2); // 回傳 2
int last = Array.FindLast(numbers, i => i % 2 == 0); // 回傳最後一個偶數
int[] evens = Array.FindAll(numbers, i => i % 2 == 0); // { 2, 4, 10 }
// 配合 Array.ForEach 列印
Array.ForEach(evens, i => Console.WriteLine(i));
// 一行寫法
Array.ForEach(Array.FindAll(numbers, i => i % 2 == 0), i => Console.WriteLine(i));
int idx = Array.FindIndex(numbers, i => i == 1); // 5
int lastIdx = Array.FindLastIndex(numbers, i => i == 1); // 5 (只有一個 1)
折半搜尋:陣列必須已排序。每次比較中間元素,縮小一半搜尋範圍。時間複雜度 O(log n) vs 線性 O(n)。
int[] numbers = new int[10_000_000];
Random rnd = new Random();
for (int i = 0; i < numbers.Length; i++) numbers[i] = rnd.Next(10_000_000);
// 線性搜尋
Stopwatch sw = Stopwatch.StartNew();
int found = Array.Find(numbers, i => i == 100);
sw.Stop();
Console.WriteLine($"線性搜尋: {sw.ElapsedMilliseconds} ms");
// 二分搜尋 (含排序時間)
sw.Reset(); sw.Start();
Array.Sort(numbers); // 排序耗時
sw.Stop();
Console.WriteLine($"排序時間: {sw.ElapsedMilliseconds} ms");
sw.Reset(); sw.Start();
int idx = Array.BinarySearch(numbers, 100);
sw.Stop();
Console.WriteLine($"二分搜尋: {sw.ElapsedMilliseconds} ms");
| 操作 | 耗時 | 說明 |
|---|---|---|
| 線性搜尋 | ~50-200 ms | 視目標位置而定,最差掃描全陣列 |
| 排序 | ~1500-2500 ms | O(n log n),一次性成本 |
| 二分搜尋 | < 1 ms | 極快,但需已排序 |
Find/Exists (線性)Sort + BinarySearchSortedList、Dictionary、HashSet (O(1) 查找)
// BinarySearch 使用自訂比較
int idx = Array.BinarySearch(numbers, 100, Comparer.Create((a, b) => b - a)); // 降序陣列
// FindAll 多條件
var results = Array.FindAll(numbers, i => i > 50 && i < 100 && i % 2 == 0);
.NET 陣列搜尋方法配合 Lambda 表達式,語法極度簡潔。核心選擇在於線性 vs 二分:資料是否排序、搜尋頻率、資料量大小決定策略。理解各方法回傳值語意 (特別是找不到時的預設值),避免邏輯錯誤。