[C#.NET 拾遺補漏]02:陣列的幾個小知識

LiamWang發表於2020-06-05
閱讀本文大概需要 1.5 分鐘。

陣列本身相對來說比較簡單,能想到的可寫的東西不多。但還是有一些知識點值得總結和知曉一  下。有的知識點,知不知道不重要,工作中用的時候搜尋一下就可以了,畢竟實現一個功能程式碼的寫法有很多種,再牛的人也不可能完全熟悉一門語言的每個細節。當然了,偶然地知道了一些小知識或小技巧也是一種小小的收穫。在你看這篇小文時,或許這種偶然的事情就正在發生。我們先從陣列的初始化開始吧。

陣列的定義和初始化

定義和初始化一個陣列有好幾種方式,隨著 C# 版本升級,方式也越來越簡單:

int[] arr = new int[3];           // 定義一個長度為 3 的陣列
int[] arr = new int[3] {1, 2, 3}; // 定義一個長度為 3 的陣列並初始化
int[] arr = new [] {1, 2, 3}; // 上面的簡寫
int[] arr = {1, 2, 3}; // 上面的進一步簡寫

我們知道當定義一個固定長度的陣列沒有初始化時,比如:

int[] arr = new int[3];

雖然沒有初始化,但它是有預設值的,這個陣列中包含了 3 個值為 0 的整數。如何使用非預設值建立一個陣列呢?可以使用 System.Linq 名稱空間下的 Enumerable.Repeat 方法:

// 建立長度為 5 的整形陣列,並用 100 來填充
int[] arr = Enumerable.Repeat(100, 5).ToArray();

// 建立長度為 5 的字串陣列,並用“C#”來填充
string[] arr = Enumerable.Repeat("C#", 5).ToArray();

陣列的複製、克隆與比較

把一個陣列的元素複製到另一個陣列,可以使用 Array.Copy() 方法,複製時源陣列取值和目標陣列賦值都是從索引 0 開始的:

var sourceArray = new int[] { 11, 12, 3, 5, 2, 9};
var destinationArray = new int[3];
Array.Copy(sourceArray, destinationArray, 3);
// destinationArray = [11, 12, 3]

克隆一個陣列很簡單:

var sourceArray = new int[] { 11, 12, 3 };
var destinationArray = (int[])sourceArray.Clone();
// destinationArray = [11, 12, 3]

比較兩個陣列是否一樣,即兩個陣列包含的元素及元素的順序是否都一樣,可以使用陣列的 SequenceEqual 方法:

int[] arr1 = { 3, 5, 7 };
int[] arr2 = { 3, 5, 7 };
bool result = arr1.SequenceEqual(arr2); // true

以上只是羅列幾個有代表性的比較快捷簡單的陣列操作,在 C# 中藉助 Linq 可以實現更復雜的陣列操作,這裡先不作總結。

使用指標遍歷陣列

實際的 C#開發中很少會直接用到指標,在需要進行底層操作時可能會用到。在 C# 中使用指標時需要在 unsafe 上下文中操作:

int[] arr = new int[] {1, 6, 3, 3, 9};

// 使用 foreach
foreach (int element in arr)
{
Console.WriteLine(element);
}

// 使用指標
unsafe
{
int length = arr.Length;
fixed (int* p = arr)
{
int* pInt = p;
while (length-- > 0)
{
Console.WriteLine(*pInt);
pInt++; // 將指標移到下一個元素
}
}
}
// 依次輸出:1 6 3 3 9

這裡只是讓大家知道有這麼一回事,指標不是本篇的話題,更多關於指標的操作可以訪問:

https://bit.ly/2MmIsNl

生成有序陣列

我就見過有人使用 for 迴圈生成一個從 n 到 m 的有序陣列,其實 C# 提供了 Enumerable.Range 方法可以很容易地建立一個有序的整型陣列。示例:

// 建立數字從 1 到 100 的陣列
int[] sequence = Enumerable.Range(1, 100).ToArray();

// 結合 Linq 還可以實現更復雜的陣列建立邏輯
int[] squares = Enumerable.Range(2, 10).Select(x => x * x).ToArray(); // 3, 9, 16...

多維陣列和交錯陣列的區別

簡單來說,多維陣列每一行長度都是固定的,比如二維陣列是一個 m 行 n 列的矩陣:

int[,] arr = {
{1, 2, 3, 4},
{4, 2, 1, 3},
{2, 1, 3, 4},
}

而交錯陣列(又叫鋸齒陣列)的每一行可以有不同的大小,表示的是陣列的陣列。比如:

int[][] arr = {
new [] {1, 2, 3, 4},
new [] {1, 2},
new [] {1, 2, 3},
}

它們的定義、初始化、取值、賦值等都有明顯的區別。

先看多維陣列:

// 多維陣列的定義
int[,] arr = new int[10, 10]; // 二維陣列
int[,,] arr = new int[10, 10, 10]; // 三維陣列

// 多維陣列的初始化 (new int[3, 2] 可以省略)
int[,] arr = new int[3, 2] { {1, 1}, {2, 2}, {3, 3} };

// 多維陣列的取值
Console.WriteLine(arr[2, 1]); // 3

// 多維陣列的賦值
arr[2, 1] = 10;

再對比交錯陣列:

// 交錯陣列的定義
int[][] arr = new int[10][]; // 二層:陣列的陣列
int[][][] arr = new int[10][][]; // 三層:陣列的陣列的陣列

// 交錯陣列的初始化 (new int[3][] 可以省略)
int[][] arr = new int[3][] { new [] {1}, new [] {2, 2}, new [] {3, 3, 3} };

// 交錯陣列的取值
Console.WriteLine(arr[2][1]); // 3

// 多維陣列的賦值
arr[2][1] = 10;

注意:多維陣列每行長度必須一致;交錯陣列第二個 [] 是不能有數字的。兩者的 Length 屬性意義也是不一樣的,多維陣列的 Length 屬性取的是陣列所有元素的總數,而交錯陣列取的是第一層的陣列的個數。例如:

int[,] arr1 = new int[3, 2] { { 1, 1 }, { 2, 2 }, { 3, 3 } };
Console.WriteLine(arr1.Length); // 輸出:6

int[][] arr2 = new int[3][] { new[] { 1 }, new[] { 2, 2 }, new[] { 3, 3, 3 } };
Console.WriteLine(arr2.Length); // 輸出:3

建議:除了某些像矩陣這樣的操作場景可能更適合使用多維陣列,大多數場景應儘量選擇使用交錯陣列。功能上多維陣列可以實現的,交錯陣列也都能實現,反過來不一定可以。另外,根據 stackoverflow 網友的回答(下面參考連結),在 .NET 中,交錯陣列效能上要好於多維陣列。

參考:https://bit.ly/2Mqn6P1

相關文章