Lập trình C#

Lớp System.Array trong lập trình C#

Lớp System.Array trong lập trình C#
Được viết bởi Minh Hoàng

Series lập trình C#, ngôn ngữ lập trình hiện đại và mạnh mẽ.

– Trong bài viết này, chúng ta sẽ cùng tìm hiểu về lớp System.Array trong lập trình C#. Lớp System.Array là một lớp rất quan trọng để đơn giản hóa thao tác với mảng.

– Trong các chương trình thì chúng được dùng rất phổ biến, có thể dùng trực tiếp hoặc gián tiếp, nhưng chắc chắn khi bạn dùng và làm việc với các cấu trúc dữ liệu thì sẽ sử dụng đến lớp System.Array.

– Khai báo một mảng số nguyên gồm 6 phần tử:

int[] sourceArr = new int[] { 8, 6, 2, 9, 1, 7 };

– Một số phương thức của lớp System.Array sẽ được giới thiệu trong bài viết này:

  1. Set các giá trị của mảng về giá trị mặc định với Array.Clear()
  2. Sao chép dữ liệu mảng
    • Array.Copy()
    • Array.ConstrainedCopy()
    • Sự khác khau của 2 phương thức Array.Copy() và Array.ConstrainedCopy()
  3. Thay đổi kích thước mảng với Array.Resize()
  4. Đảo ngược phần tử mảng với Array.Reverse()
  5. Tìm kiếm phần tử trong mảng
    • Tìm kiếm tuần tự với Array.IndexOf()
    • Tìm kiếm tuần tự với Array.LastIndexOf()
    • Tìm kiếm nhị phân với Array.BinarySearch()
  6. Sắp xếp mảng
    • Đối với kiểu dữ liệu có sẵn của .Net
    • Đối với kiểu dữ liệu tự định nghĩa
1. Set các giá trị của mảng về giá trị mặc định
#1. Set các giá trị của mảng về giá trị mặc định
Array.Clear(Array array, int index, int length);

– Trong đó:
Array array : mảng muốn reset giá trị.
int index : vị trí bắt đầu muốn reset.
int length : số lượng phần tử muốn reset.

– Ví dụ:

[code language=”csharp”] // Set toàn bộ giá trị của mảng về giá trị mặc định
Array.Clear(sourceArr, 0, sourceArr.Length);

// Set các giá trị của mảng từ vị trí 1 -> 3 về giá trị mặc định
Array.Clear(sourceArr, 1, 3);
[/code]

2. Sao chép dữ liệu mảng
#2. Sao chép dữ liệu mảng

– Chúng ta cần tạo ra một mảng mới destArr có kích thước lớn hơn hoặc bằng mảng ban đầu sourceArr.

[code language=”csharp”] // Tạo vùng nhớ cho mảng đích trước khi copy
int[] destArr = new int[sourceArr.Length];
[/code]

– Các phương thức sao chép dữ liệu mảng:

Array.Copy có 4 overload như sau:

Array.Copy(Array sourceArray, Array destinationArray, int length);
Array.Copy(Array sourceArray, Array destinationArray, long length);
Array.Copy(Array sourceArray, long sourceIndex, Array destinationArray, long destinationIndex, long length);
Array.Copy(Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length);

– Trong đó:

  • Array sourceArray : mảng nguồn muốn copy giá trị.
  • int sourceIndex : vị trí bắt đầu copy giá trị ở mảng nguồn.
  • Array destinationArray : mảng đích để lưu trữ giá trị.
  • int destinationIndex : vị trí bắt đầu lưu trữ giá trị ở mảng đích.
  • int length : số lượng phần tử muốn copy.

– Ví dụ:

[code language=”csharp”] // Copy toàn bộ giá trị của mảng nguồn vào mảng đích
Array.Copy(sourceArr, 0, destArr, 0, sourceArr.Length);

// Copy [3] giá trị từ vị trí thứ [2] của mảng nguồn
// vào vị trí đầu tiên [0] trở đi ở mảng đích
Array.Copy(sourceArr, 2, destArr, 0, 3);
[/code]

Array.ConstrainedCopy

Array.ConstrainedCopy(Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length);

– Trong đó:

  • Array sourceArray : mảng nguồn muốn copy giá trị.
  • int sourceIndex : vị trí bắt đầu copy giá trị ở mảng nguồn.
  • Array destinationArray : mảng đích để lưu trữ giá trị.
  • int destinationIndex : vị trí bắt đầu lưu trữ giá trị ở mảng đích.
  • int length : số lượng phần tử muốn copy.

– Ví dụ:

[code language=”csharp”] // Copy toàn bộ giá trị của mảng nguồn vào mảng đích
Array.ConstrainedCopy(sourceArr, 0, destArr, 0, sourceArr.Length);

// Copy [3] giá trị từ vị trí thứ [2] của mảng nguồn
// vào vị trí đầu tiên [0] trở đi ở mảng đích
Array.ConstrainedCopy(sourceArr, 2, destArr, 0, 3);
[/code]

■ Sự khác nhau của 2 phương thức Array.CopyArray.ConstrainedCopy

– Cả 2 phương thức này khi copy mà có lỗi hay exception xảy ra thì đối với:

  • Array.Copy : giá trị đã copy thành công từ mảng nguồn vẫn được lưu trữ ở mảng đích.
  • Array.ConstrainedCopy : giá trị đã copy thành công từ mảng nguồn không được lưu trữ ở mảng đích, mà toàn bộ giá trị của mảng đích sẽ được reset lại giá trị mặc định.

– Để hiểu hơn về điều này, chúng ta cùng phân tích đoạn code sau:

[code language=”csharp”] // Khai báo mảng kiểu object 3 phần tử
object[] objArray = { "MinhHoangBlog", "minhhn.com", 999 };

// Khai báo mảng kiểu string 3 phần tử
string[] stringArray = new String[3];
[/code]

Trường hợp sử dụng Array.Copy

Array.Copy(objArray, stringArray , 3);

・ Khi chạy cho dù phát sinh exception (System.InvalidCastException) thì 2 phần tử đầu tiên của mảng nguồn objArray đã được sao chép thành công vào mảng đích stringArray vẫn được lưu lại.

Result run method Array.Copy

Result run method Array.Copy


Trường hợp sử dụng Array.ConstrainedCopy

Array.ConstrainedCopy(objArray, 0, stringArray, 0, 3);

・ Khi chạy phát sinh exception (System.ArrayTypeMismatchException) thì sẽ không sao chép bất kỳ phần tử nào của mảng nguồn objArray vào mảng đích stringArray.

Result run method Array.ConstrainedCopy

Result run method Array.ConstrainedCopy


– Do đó, tùy vào trường hợp cụ thể khi copy có lỗi hay exception xảy ra bạn muốn lưu giá trị vào mảng mới hay không mà sử dụng linh hoạt 2 phương thức này nhé.

3. Thay đổi kích thước mảng
#3. Thay đổi kích thước mảng

– Đối với biến khai báo kiểu Array thì chúng ta không thay đổi được số lượng phần tử. Ở đây chúng ta khai báo mảng sourceArr là 6 phần tử thì mảng sẽ là cố định và không thay đổi được.

– Và nếu muốn thay đổi thì cần dùng đến phương thức Array.Resize. Thực chất phương thức này không phải thực hiện thay đổi kích thước mảng, mà nó thực hiện bằng cách:

  1. Tạo một mảng mới, sau đó copy toàn bộ dữ liệu sang mảng mới này.
  2. Cuối cùng là gán tham chiếu lại vào mảng cũ, vì thế mà trong cú pháp sử dụng từ khóa ref đi kèm với tên mảng muốn resize.
Array.Resize(ref T[] array, int newSize);

– Trong đó:
ref T[] array : tên biến mảng muốn thay đổi kích thước, đi kèm với từ khóa ref.
int newSize : kích thước mới muốn thay đổi.

– Ví dụ:

[code language=”csharp”] // Tăng size mảng lên 1, phần tử mới sẽ có giá trị mặc định theo kiểu dữ liệu của mảng
// ở đây mảng integer nên giá trị của phần tử mới bằng 0
Array.Resize(ref sourceArr, sourceArr.Length + 1);

// Giảm size mảng chỉ còn 2 phần tử và giá trị giữ nguyên không thay đổi:
// sourceArr[0] = 8 và sourceArr[1] = 6
Array.Resize(ref sourceArr, 2);
[/code]

4. Đảo ngược phần tử mảng
#4. Đảo ngược phần tử mảng

– Sử dụng phương thức Array.Reverse có 2 overload:

Array.Reverse(Array array);
Array.Reverse(Array array, int index, int length);

– Trong đó:
Array array : biến mảng muốn đảo ngược giá trị.
int index : vị trí bắt đầu đảo ngược.
int length : số lượng phần tử muốn đảo ngược.

– Ví dụ:

[code language=”csharp”] // Đảo ngược toàn bộ mảng
Array.Reverse(sourceArr);

// Đảo ngược [3] phần tử, tính từ vị trí thứ [2] của mảng
Array.Reverse(sourceArr, 2, 3);
[/code]

5. Tìm kiếm phần tử trong mảng
#5. Tìm kiếm phần tử trong mảng

■ Tìm kiếm tuần tự

Tìm thấy sẽ trả về index của phần tử trong mảng, không tìm thấy sẽ trả về giá trị là -1

[code language=”csharp”] // Tìm kiếm chỉ số (index) của phần tử Đầu Tiên có giá trị bằng 9
int first = Array.IndexOf(sourceArr, 9);

// Tìm kiếm chỉ số (index) của phần tử Cuối Cùng có giá trị bằng 4
int last = Array.LastIndexOf(sourceArr, 4);
[/code]

■ Tìm kiếm nhị phân

– Điều kiện: mảng cần phải được sắp xếp trước khi tìm kiếm, nếu không thì kết quả sẽ bị sai.

– Với BinarySearch thì không phân biệt phần tử đầu tiên hay cuối cùng mà chỉ quan tâm đến phần tử đã được tìm thấy. Nếu không tìm thấy sẽ trả về một giá trị âm bất kỳ nào đó chưa xác định.

– Tìm kiếm nhị phân BinarySearch có 8 overload:

Array.BinarySearch(Array array, object value);
Array.BinarySearch(Array array, object value, IComparer comparer);
Array.BinarySearch(Array array, int index, int length, object value);
Array.BinarySearch(Array array, int index, int length, object value, IComparer comparer);
Array.BinarySearch(T[] array, T value);
Array.BinarySearch(T[] array, T value, IComparer comparer);
Array.BinarySearch(T[] array, int index, int length, T value);
Array.BinarySearch(T[] array, int index, int length, T value, IComparer comparer);

– Ví dụ:

[code language=”csharp”] // Tìm kiếm nhị phân
Array.Sort(sourceArr);
int binary = Array.BinarySearch(sourceArr, 4);
[/code]
6. Sắp xếp mảng
#6. Sắp xếp mảng

– Sử dụng phương thức Array.Sort có 17 overload, mặc định là sắp xếp tăng dần:

Array.Sort(Array array);
Array.Sort(Array array, IComparer comparer);
Array.Sort(Array keys, Array items);
Array.Sort(Array keys, Array items, IComparer comparer);
Array.Sort(Array array, int index, int length);
Array.Sort(Array keys, Array items, int index, int length);
Array.Sort(Array array, int index, int length, IComparer comparer);
Array.Sort(Array keys, Array items, int index, int length, IComparer comparer);
Array.Sort(T[] array);
Array.Sort(T[] array, IComparer comparer);
Array.Sort(T[] array, Comparison comparison);
Array.Sort(T[] array, int index, int length);
Array.Sort(T[] array, int index, int length, IComparer comparer);
Array.Sort(TKey[] keys, TValue[] items);
Array.Sort(TKey[] keys, TValue[] items, IComparer comparer);
Array.Sort(TKey[] keys, TValue[] items, int index, int length);
Array.Sort(TKey[] keys, TValue[] items, int index, int length, IComparer comparer);

– Ví dụ:

[code language=”csharp”] // Sắp xếp tăng dần toàn bộ mảng
Array.Sort(sourceArr);

// Sắp xếp tăng dần [3] phần tử, tính từ vị trí thứ [2] của mảng
Array.Sort(sourceArr, 2, 3);
[/code]

– Đối với kiểu dữ liệu có sẵn như: int, double, string,… thì đã được .Net hỗ trợ phương thức so sánh rồi nên chúng ta sử dụng phương thức Sort() được bình thường như trên.

– Nhưng với kiểu dữ liệu custom, do lập trình viên tự định nghĩa sẽ chưa được hỗ trợ phương thức so sánh, khi đó nếu dùng phương thức Sort() kết quả thu được sẽ không đúng hoặc sẽ phát sinh exception. Khi đó, kiểu custom cần thực thi interface IComparable, IComparable<T>. Như ví dụ sau:

[code language=”csharp” highlight=”19,27,33-38,50,56-68″] using System;

namespace MinhHoangBlog
{
class Program
{
static void Main(string[] args)
{
// Sort custom type
Person2[] person = new Person2[] {
new Person2 { Age = 1, Name = "MinhHoang" },
new Person2 { Age = 4, Name = "Blog" },
new Person2 { Age = 2, Name = "Welcome" },
new Person2 { Age = 3, Name = "To" },
new Person2 { Age = 2, Name = "Minhhn.com" }
};

Array.Sort( person );

Console.ReadKey();
}
}

// Cách 1: Kiểu dữ liệu custom Person1
// Implement interface IComparable
class Person1 : IComparable
{
public string Name { get; set; }

public int Age { get; set; }

// Implement method CompareTo
public int CompareTo(object obj)
{
// Chỉ sắp xếp theo Age
return Age – ((Person1)obj).Age;
}

public override string ToString()
{
return string.Format("{0}, {1}", Age, Name);
}
}

// Cách 2: Kiểu dữ liệu custom Person2
// Implement interface generic IComparable<T>
// Lúc này T sẽ thay bằng kiểu Person2, do đó lúc so sánh (CompareTo)
// không cần ép kiểu về Person2 như Cách 1 nữa.
class Person2 : IComparable<Person2>
{
public string Name { get; set; }

public int Age { get; set; }

// Implement method CompareTo
public int CompareTo(Person2 ps)
{
// Sắp xếp theo Age
int result = Age – ps.Age;
if (0 == result)
{
// Trường hợp mà Age bằng nhau, sẽ sắp xếp theo Name
result = this.Name.CompareTo(ps.Name);
}

return result;
}

public override string ToString()
{
return string.Format("{0}, {1}", Age, Name);
}
}
}
[/code]

– Khi thực thi chương trình trên, chúng ta có kết quả như sau:
・ Trước khi sắp xếp:

Kiểu custom Person chưa sắp xếp

Kiểu custom Person chưa sắp xếp


・ Sau khi sắp xếp:
Kiểu custom Person đã sắp xếp

Kiểu custom Person đã sắp xếp

Cảm ơn bạn đã theo dõi. Đừng ngần ngại hãy cùng thảo luận với chúng tôi!

Giới thiệu

Minh Hoàng

Xin chào, tôi là Hoàng Ngọc Minh, hiện đang làm BrSE, tại công ty Toyota, Nhật Bản. Những gì tôi viết trên blog này là những trải nghiệm thực tế tôi đã đúc rút ra được trong cuộc sống, quá trình học tập và làm việc. Các bài viết được biên tập một cách chi tiết, linh hoạt để giúp bạn đọc có thể tiếp cận một cách dễ dàng nhất. Hi vọng nó sẽ có ích hoặc mang lại một góc nhìn khác cho bạn[...]

1 bình luận

Translate »