Subrange, Enum, Set
Kiểu đoạn con, liệt kê và tập hợp
Kiểu đoạn con, liệt kê và tập hợp
Kiểu subrange (đoạn con) là kiểu dữ liệu tự định nghĩa, xác định một phạm vi giá trị nằm giữa hai chỉ số đầu và cuối. Các biến thuộc kiểu subrange bắt buộc phải nằm trong phạm vi đã xác định.
type
TChuHoa = 'A' .. 'Z';
TChuThuong = 'a' .. 'z';
TChuSo = '0' .. '9';
TNhoHon100 = 0 .. 99;
Kiểu subrange có thể sử dụng cho số, kí tự và cả kiểu enum. Subrange được khai báo bằng từ khóa type theo sau là hai chỉ số ngăn cách bởi 2 dấu chấm ..
Lưu ý: Chỉ số sau phải lớn hơn chỉ số trước.
Kiểu subrange thường được sử dụng nhiều trong tập hợp (set).
Nếu một biến kiểu subrange vượt ra ngoài phạm vi của nó, compiler sẽ báo lỗi khi biên dịch. Như ví dụ sau, compiler sẽ báo lỗi tại dòng gán thứ hai.
var
A: TNhoHon100;
begin
A := 50; // Không có lỗi
A := 150; // Có lỗi
end;
Kiểu enum (enumeration - kiểu liệt kê) là một kiểu dữ liệu khá hữu dụng, nó giúp chúng ta gắn một số cho một tên biến có nghĩa mà không cần khai báo hằng.
Ví dụ như các ngày trong tuần, thay vì phải khai báo các hằng như sau
const
Sunday = 1;
Monday = 2;
Tuesday = 3;
Wednesday = 4;
Thursday = 5;
Friday = 6;
Saturday = 7
Thì kiểu enum cho phép chúng ta liệt kê chúng trong một kiểu dữ liệu duy nhất.
type
TDay = (Noday, Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday);
Ở trên, mình sử dụng thêm một giá trị nữa là noday, có nghĩa là một ngày không xác định (chưa được gán).
Các phần tử trong enum được tự động đánh chỉ số từ 0. Như trên Noday = 0, Sunday = 1, Monday = 2, ... tuy nhiên, bạn có thể đánh số tùy chỉnh cho các phần tử này một cách tự do, với điều kiện không được trùng nhau.
type
TTraiCay = (Apple = 3, Kiwi = 0, Banana = 2, Orange = 1);
A. Biến kiểu enum
Một biến thuộc kiểu enum (được khai báo bằng var) có thể gán cho bất kì phần tử nào của enum.
var
Today: TDay;
begin
Today := Monday;
Today := Tuesday;
...
end;
B. So sánh phần tử enum
Các phần tử enum đều được đánh chỉ số (index) bắt đầu từ 0 dựa trên thứ tự sắp xếp của chúng. Vì thế, so sánh hai phần tử enum cũng giống như so sánh 2 số.
Với ví dụ TDay ở trên, thì.
Monday < Tuesday
Friday = Friday
Saturday > Sunday
Friday <> Thursday
C. Vòng lặp
Chúng ta có thể sử dụng cấu trúc lặp để lặp hết các phần tử của enum hoặc một số phần tử nhất định. Ví dụ như thứ ngày ở trên, ta có thể sử dụng các giá trị enum làm chỉ số.
var
Today: TDay;
begin
for Today := Monday to Saturday do
LamViec;
end;
Trong một số trường hợp, bạn không biết rõ đâu là phần tử đầu và phần tử cuối của enum, bạn có thể sử dụng vòng lặp for ... in.
var
Today: TDay;
begin
for Today in TDay do
LamViec;
end;
Tập hợp trong delphi cũng giống với tập hợp trong toán, gồm các phần tử cùng kiểu với nhau và không trùng nhau. Trong delphi, tập hợp có số phần tử tối đa là 255.
Các phần tử của tập hợp là những kiểu dữ liệu đơn giản như số nguyên và kí tự.
Delphi sử dụng kĩ thuật gọi là bitwise để quản lý các phần tử. Thế nên bạn có thể sử dụng các toán tử bit như and, or, xor, not để thực hiện thêm hoặc xóa phần tử trong set.
Các hằng tập hợp được ghi trong cặp dấu [ và ].
A. Khai báo tập hợp
Tập hợp được khai báo bằng cụm từ khóa set of.
type
TIntSet = set of Byte;
TCharSet = set of Char;
var
IntSet: TIntSet;
CharSet: TCharSet;
Các phần tử của tập hợp được đặt trong dấu ngoặc vuông [ và ], ngăn cách nhau bởi dấu phẩy. Có thể sử dụng kiểu subrange bên trong tập hợp.
begin
IntSet := [1, 2, 3, 4, 5];
CharSet := ['A'..'Z', 'a'..'z'];
end;
Lưu ý: Các phần tử trong tập hợp không được trùng nhau.
B. Các phép toán trên tập hợp
Các phép toán trên tập hợp gồm 2 phép chính:
Phép so sánh: Bằng (=) và khác (<>). Phép bằng khi hai set có các phần tử giống nhau, ngược lại là khác.
Phép cộng, trừ, nhân: Không có phép chia. Phép cộng tìm hợp của các phần tử 2 set (tất cả các phần tử). Phép trừ tìm ra phần tử nào set A có mà set B không có. Phép nhân tìm ra giao của 2 set (các phần tử cả 2 set đều có)
var
Set1, Set2, Set3: set of Byte;
begin
Set1 := [1, 2, 5];
Set2 := [2, 5, 10, 4];
if Set1 = Set2
then writeln('Set1 bang Set2')
else writeln('Set1 khac Set2');
Set3 := Set1 + Set2; // Set3 = [1, 2, 5, 10, 4]
Set3 := Set1 - Set2; // Set3 = [1];
Set3 := Set2 - Set1; // Set3 = [10, 4];
Set3 := Set1 * Set2; // Set3 = [2, 5];
end;
C. Toán tử IN
Dùng toán tử in để xác định xem một giá trị nào đó có nằm trong set hay không.
var
aSet: set of Byte;
begin
aSet := [1, 3, 5, 7];
if 5 in aSet then
writeln('So 5 co trong tap hop')
else
writeln('So 5 khong co trong tap hop');
end;
D. Vòng lặp For ... in
Để lặp hết các phần tử trong set, chúng ta không thể dùng vòng lặp for ... do được vì các phần tử của set không có chỉ số (khác với enum). Thay vào đó, sử dụng vòng lặp for ... in (tương tự như For Each trong các ngôn ngữ khác).
var
NumberSet: set of Byte;
aNumber: Byte;
begin
NumberSet := [2, 4, 6, 8];
for aNumber in NumberSet do
writeln(aNumber);
end;
Với mỗi lần lặp, aNumber (biến chạy) sẽ mang một giá trị trong NumberSet. Các giá trị này khác nhau mỗi lần. Khi hết tập hợp, vòng lặp sẽ dừng lại.