Kiểu dữ liệu của Array, List trong C#

Array (Mảng)
Mảng là một tập hợp các kiểu dữ liệu giống nhau và được xác định tại những vị trí liều kề nhau trong bộ nhớ. Các phần tử của mảng có thể được truy cập trực tiếp qua chỉ số của phần tử đó trong mảng. Trong C#, khi một mảng được tạo ra, chúng sẽ có giá trị null. Đoạn code sau khởi tạo một mảng kiểu bool: bool [] booleanArray;
Trước khi có thể thao tác với mảng thì chúng ta phải tạo một thể hiện của mảng mà để lưu các phần tử. Cú pháp như sau: booleanArray = new bool[10];
hoặc chúng ta có thể vừa khởi tạo, vừa tạo thể hiện của mảng: bool [] booleanArray = new bool[10];

Mọi mảng trong .NET cho phép các phần tử có thể đọc và viết giá trị vào đó. Cú pháp như sau:

//Read an array element
bool b = booleanArray[7];

//Write an array element
booleanArray[2] = false;

Trong managed code, CLR sẽ kiểm tra để đảm bảo là các phần tử truy nhập nằm trong giới hạn của mảng, nếu không thì một ngoại lệ sẽ được ném ra: IndexOutOfRangeException.

Khi làm việc với mảng, đôi khi chúng ta cần thay đổi kích thước của mảng. Để làm được điều này, chúng ta phải tạo một thể hiện mới của mảng với kích thước mới, sao chép nội dung mảng cũ sang mảng mới. Đoạn code sau mô tả quá trình đó:

// Create an integer array with three elements
int [] fib = new int[3];
fib[0] = 1;
fib[1] = 1;
fib[2] = 2;

// Redimension message to a 10 element array
int [] temp = new int[10];

// Copy the fib array to temp
fib.CopyTo(temp, 0);

// Assign temp to fib
fib = temp;

Sau dòng code cuối thì mảng fib có thể tham chiếu được tới 10 phần tử. Giá trị từ 3 – 9 sẽ mang giá trị mặc định của kiểu Int32 là 0

Tạo Cấu trúc dữ liệu thực thi an toàn, có thể tái sử dụng
Khi tạo một cấu trúc dữ liệu cho một vấn đề nào đó, thường thì cấu trúc đó được tùy chỉnh theo yêu cầu của công việc. Ví dụ, để quản lí bảng lương nhân viên, các giá trị đầu vào là các nhân viên, chúng ta có thể tạo một lớp Employee với các phương thức và thuộc tính phù hợp. Và để biểu diễn một tập hợp các nhân viên, chúng ta có thể sử dụng một mảng Employee, nhưng bạn lại cần có thêm các chức năng bổ sung mà không muốn quan tâm đến việc thay đổi kích thước mảng khi cần thiết. Một tùy chọn đó là tự tạo một cấu trúc dữ liệu riêng cho kiểu Employee, thêm vào đó các chức năng cần thiết như tìm kiếm, tăng kích thước….

Cấu trúc này tỏ ra hữu dụng trong ứng dụng của bạn nhưng khi đem sử dụng cho các ứng dụng khác thì lại không được vì nó chỉ lưu trữ các phần tử là kiểu Employee. Để tạo cấu trúc dữ liệu thêm linh hoạt, ta có thể tạo một mảng của các thể hiện Object. Bởi vì tất cả các kiểu dữ liệu đều là dẫn xuất từ kiểu Object nên nó có thể lưu bất kì giá trị nào. .NET Framework cung cấp một cấu trúc cho việc này: lớp System.Collections.ArrayList. ArrayList chứa một mảng các phần tử có kiểu là Object nên nó có thể lưu bất kì kiểu giá trị nào: strings, integers, đối tượng FileInfo, các thể hiện của Form ….

Mặc dù ArrayList tỏ ra khá hữu hiệu và linh hoạt nhưng lại phải đổi lại bằng hiệu năng của ứng dụng. Vì ArrayList lưu mảng các object, và khi đọc giá trị thì phải ép kiểu giá trị. Một mảng ArrayList thì dù cho bạn không có lưu trữ bất cứ phần tử nào thì mỗi phần tử là một tham chiếu tới một kiểu giá trị được boxed (boxed value type) => tốn bộ nhớ.

Sử dụng ArrayList với số lượng phần tử lớn có thể làm chậm việc thực thi chương trình. Ngoài ra, vì ArrayList cho phép bất cứ kiểu giá trị nào cũng có thể được thêm vào nên sẽ không có lỗi xảy ra khi thêm một kiểu không hợp lệ. Các lỗi này sẽ không xuất hiện đến khi kiểm tra hoặc đem ra sử dụng.

Tuy nhiên, trong .NET Framework 2.0, chúng ta có Generics để giải quyết vấn đề của ArrayList. Generics là một namespace cho phép tạo một cấu trúc dữ liệu theo một cách khác. Developer có thể tùy chọn kiểu dữ liệu sử dụng . Để hiểu rõ hơn thì chúng ta xét một ví dụ:

public class TypeSafeList
{
T[] innerArray = new T[0];
int currentSize = 0;
int capacity = 0;

public void Add(T item)
{
// see if array needs to be resized
if (currentSize == capacity)
{
// resize array
capacity = capacity == 0 ? 4 : capacity * 2; // double capacity
T[] copy = new T[capacity]; // create newly sized array
Array.Copy(innerArray, copy, currentSize); // copy over the array
innerArray = copy; // assign innerArray to the new, larger array
}

innerArray[currentSize] = item;
currentSize++;
}

public T this[int index]
{
get
{
if (index = currentSize)
throw new IndexOutOfRangeException();
return innerArray[index];
}
set
{
if (index = currentSize)
throw new IndexOutOfRangeException();
innerArray[index] = value;
}
}

public override string ToString()
{
string output = string.Empty;
for (int i = 0; i < currentSize – 1; i++)
output += innerArray[i] + ", ";

return output + innerArray[currentSize - 1];
}
}

Tại dòng đầu tiên, chúng ta có thành phần định nghĩa kiểu T. Developer sẽ dùng nó để chỉ định một kiểu, mà ở đây chúng ta định danh là T. Chúng ta hoàn toàn có thể dùng các tên khác thay cho T, và biến này có thể được sử dụng trong các phương thức và thuộc tính.

Để khai báo biến cho class này, developer cần chỉ định kiểu T, như:

TypeSafeList varibaleName;

Đoạn code sau mô tả việc tạo một thể hiện của TypeSafeList lưu trữ số nguyên và đưa giá trị là 25 số Fibonacci vào:

TypeSafeList fib = new TypeSafeList();
fib.Add(1);
fib.Add(1);
for (int i=2; i<25; i++)
fib.Add(fib[i-1] + fib[i-2]);
Console.WriteLine(fib.ToString());

Lợi ích của việc sử dụng Generics là:

-An toàn kiểu: developer chỉ có thể thêm vào một kiểu được chỉ định.
-Performance: chương trình thực thi nhanh hơn và hiệu quả hơn
-Có thể tái sử dụng

Rất nhiều cấu trúc dữ liệu, ví dụ như cây nhị phân, chúng ta sẽ dùng tới Generics

List: Mảng đồng nhất, tự thay đổi số chiều.
Trong phần trước, chúng ta đã tạo ra một lớp TypeSafeList, tuy nhiên, .NET Framework cung cấp sẵn một lớp tương tự như vậy cho chúng ta mà chúng ta không cần quan tâm nhiều đến việc viết code. Đó là lớp List, được chứa trong namespace System.Collections.Generics

Để tạo một thể hiện của List, ta làm giống như ví dụ ở phần trước:

//Tạo một danh sách các số nguyên
List myFavouriteIntegers = new List();

//Tạo một danh sách chuỗi
List friendsNames = new List();

Khi khởi tạo, chúng ta không cần chỉ ra kích thước của List (mặc dù chúng ta có thể chỉ định một kích thước mặc định trước qua constructor hoặc qua thuộc tính List’s Capacity). Để thêm vào một phần tử, ta dùng phương thức Add(), và chúng ta có thể truy cập trực tiếp và các phần tử thông qua chỉ số của phần tử đó. Sau đây là một đoạn code mô tả việc tạo một List các số nguyên, và sau đó là thêm, đọc, ghi giá trị:

// Create a List of integers
List powersOf2 = new List();

// Add 6 integers to the List
powersOf2.Add(1);
powersOf2.Add(2);
powersOf2.Add(4);
powersOf2.Add(8);
powersOf2.Add(16);
powersOf2.Add(32);

// Change the 2nd List item to 10
powersOf2[1] = 10;

// Compute 2^3 + 2^4
int sum = powersOf2[2] + powersOf2[3];

List cung cấp cho ta nhiều phương thức hỗ trợ cho các công việc thường làm. Ví dụ, muốn tìm một phần tử trong một mảng, bạn cần viết một vòng lặp for để thực hiện. Trong List, bạn chỉ cần đơn giản gọi thủ tục Contains() để xem có phần tử nào đó trong mảng không, hay IndexOf() để tìm vị trí của phần tử. Lớp List cũng có phương thức BinarySearch() để tìm một phần tử trong mảng đã được sắp xếp, và các phương thức Find(), FindAll(), Sort(), ConvertAll().
Nguồn bài viết: Dngaz.com

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: