Contents
Chào mừng bạn đến với Fx Studio. Chúng ta lại tiếp tục với chuyến du lịch không đồng với ngôn ngữ lập trình Dart. Trong nhiều ngôn ngữ lập trình, thì các Collections (List, Set, Map) đều có và đôi khi chúng có thể gọi tên khác nhau. Nhưng hầu như về bản chất, thì sẽ giống nhau và ta sẽ có những toán tử cao cấp hơn để quản lý hay xử lý các phần tử trong các Collections. Gọi là higher order methods (ví dụ: map, filter, reduce, ..). Bài viết này sẽ giúp bạn tìm hiểu Collections trong Dart có gì.
Nếu bạn chưa biết về 3 kiểu dữ liệu đặc trưng mà chúng ta sẽ nhắc tới rất nhiều trong bài viết này, thì bạn có thể tham khảo các link sau:
Còn nếu mọi việc đã ổn rồi, thì …
Bắt đầu thôi!
Chuẩn bị
Về mặt công cụ editor thì khá đơn giản:
- TextEditor
- Visual Studio Code (nên dùng)
Hoặc bạn vào trang https://dartpad.dev/ để tiến hành code luôn. Khá là giống với Playground của Swift.
Về mặt lý thuyết, nếu bạn chưa biết gì về Dart, thì có thể theo dõi lại các bài viết trong series Dart Tour nhóe.
Collections Type
Đây là một khái niệm được dùng cho các kiểu dữ liệu tập hợp trong một ngôn ngữ lập trình nào đó. Các đối tượng của các kiểu dữ liệu đó có thể mang trong mình nhiều đối tượng của các kiểu dữ liệu khác. Nghe qua thì cũng khá rối, nhưng bạn đã gặp và làm việc khá nhiều rồi đó.
Với Dart, ta có 3 kiểu dữ liệu đại diện là:
List type
List hay còn gọi là Array theo cái tên dân gian lập trình thường dùng.
Đây là một kiểu dữ liệu phổ biến nhất trong Dart cũng như trong các ngôn ngữ lập trình khác.
Nó có những đặc điểm cơ bản sau:
- Là một cấu trúc dữ liệu để sắp xếp thứ tự các đối tượng.
- Các đối tượng trong List thì có cùng kiểu dữ liệu với nhau
- Phần tử đầu tiên sẽ có
index = 0
- Thứ tự các phần tử trong một danh sách rất quan trọng.
Set type
Set cũng là một kiểu cấu trúc dữ liệu tập hợp.
Nhưng các phần tử trong tập hợp là duy nhất. Ta có một số đặc tính riêng của Set như sau:
- Là tập hợp mà mỗi phần tử tồn tại trong đó là duy nhất
- Các phần tử có cùng kiểu dữ liệu
- Thứ tự các phần tử không ảnh hưởng và không quan trong. Set luôn duy trì một thứ tự đặc biết dựa theo giá trị của các phần tử.
index
trong Set không có ý nghĩa- Set có tốc độ truy cập & xử lý nhanh hơn List. Đặt biệt với các dữ liệu lớn
- Ta có thể sử dụng các phép toán logic trên Set
Map Type
Map Type trong Dart cũng là một cấu trúc dữ liệu tập hợp.
Map Type còn được xem là một kiểu từ điển, tức là với mỗi key
sẽ có value
tương tứng. Và ta có các đặc điểm sau cho Map.
- Các phần tử là 1 cặp giá trị, bao gồm
key
&value
- Không có yêu cầu về thứ tự trong Map
- Các
key
phải cũng kiểu dữ liệu với nha vàvalue
cũng vậy - Giữa
key
&value
có thể khác kiểu dữ liệu - 1
key
trong Map là tồn tại duy nhất. - Để tìm tới giá trị của một phần tử thì phải dựa vào
key
của nó
Nghe qua có thể bạn mông lung một chút. Nhưng đây chính là kiểu dữ liệu mô tả cho kiểu dữ liệu JSON mà bạn sẽ phải tương tác khi muốn làm việc với các API.
Iterable
Đây là một kiểu dữ liệu bị bỏ quên khá nhiều. Nhưng mà nó được xem là một Collections khá nguyên thủy.
Nếu bạn tinh ý thì sẽ thấy khi print
lại có 2 kiểu khác nhau, đó là 2 dấu ()
và []
. Với dấu ()
thì gọi là Iterable of int.
Iterable là một lớp generic biểu diễn tập hợp dữ liệu mà có thể duyệt qua hết phần tử này đến phần tử khác. Nghĩa là nó hỗ trợ moveNext()
để đi đến phần tử tiếp theo, lấy dữ liệu phần tử hiện tại bằng iterator.current
.
Thường thì Iterable được tạo ra, liên kết với một loại kiểu dữ liệu tập hợp khác như List, Map … Từ Iterable bạn có thể chuyển đổi sang List & Set thông qua các toán tử .toList()
& .toSet()
Ví dụ nhóe:
//Sinh ra Iterable chứa 100 phần tử số từ 0 - đến 99 var iterable = new Iterable.generate(100); for (var item in iterable) { print(item); } //0 //1 ... //99 // Sử dụng ForEach iterable.forEach((f) { print(f); });
Nếu có cơ hội thì mình sẽ làm một viết về Iterable sau nhóe, nó cũng khá là hay à.
Higher Order Methods
Tiếp theo, chúng ta sẽ khám phá các Higher Order Methods được sử dụng nhiều với các kiểu dữ liệu Collections nhóe!
mapping
Đây là toán tử map
(hay gọi là mapping) chứ không phải là kiểu dữ liệu Map. Tên tiếng Việt thân thiện sẽ gọi là
Phép ánh xạ
Phép ánh xạ cho một collections sẽ giúp bạn thực hiện một hành động trên từng phần tử của tập hợp, hiểu nôm na như là một vòng lặp. Phương thức map
là một anonymous function và kết quả return lại là một collections.
Bạn xem qua ví dụ code sau nhoé:
const nums = [1, 2, 3, 4]; final squares = nums.map((nums) => nums * nums); print(squares); //(1, 4, 9, 16)
Trong đó,
- Yêu cầu bài toán là tạo một danh sách mới với các phần tử sẽ là bình phương của từng phần tử List
nums
- Sử dụng toán tử
map
và tham số chính lànums
& phép biến đổi lànums * nums
- Kết quả trả về cho
squares
và chúng ta có một danh sách mới
Quan trọng là danh sách nums
không bị thay đổi. Đây là điểm khác với các toán tử lặp khác.
print(nums); //[1, 2, 3, 4]
filtering
Tiếp theo, bạn có thể lặp và lọc một tập hợp để thu lại được một tập hợp nhỏ hơn. Chúng ta sử dụng toán tử where
. Cách dùng cũng tương tự như map
. Nhưng nó sẽ cho phép các phần tử có thể được thêm vào tập hợp mới, nếu thỏa mãn được một điều kiện nào đó.
Xem ví dụ code nhoé!
final evens = squares.where((square) => square.isEven); print(evens); //(4, 16)
Trong đó:
- Kết quả trả về là một tập hợp kiểu Iterable
- Điều kiện lọc ở đây là
.isEven
tức là lặp ra các phần tử chẵn từ listsquares
reduce
Đây được xem là toán tử hợp nhất. Khi bạn muốn tính toán dựa trên toàn bộ số phần tử của tập hợp. Ví dụ: tính tổng các phần tử trong tập hợp. Bạn có thể tuỳ ý thực hiện việc tính toán hoặc hợp nhất theo một quy luật nào đó mà bạn nghĩ ra.
Xem ví dụ:
const amounts = [199, 299, 299, 199, 499]; final total = amounts.reduce((sum, element) => sum + element); print(total); //1495
Trong đó:
- Cứ mỗi bước lặp thì
sum
sẽ được cộng thêmelement
vào. - Sau đó
sum
sẽ gán lại chosum
ở bước lặp tiếp theo
fold
Đây là toán tử tối ưu hơn reduce
, nếu trong trường hợp danh sách rỗng thì bạn sẽ gặp lỗi. Và fold
sẽ bắt bạn cung cấp giá trị ban đầu khi thực hiện công việc hợp nhất này.
Xem ví dụ nhoé!
final total2 = amounts.fold( 0, (int sum, element) => sum + element, ); print(total2);
Trong đó:
0
sẽ được gán chosum
trong lần chạy đầu tiên- Các lần chạy tiếp theo thì lệnh
fold
tương tự nhưreduce
sorting
Sorting (sắp xếp) được xem là một trong những toán tử kinh điển của mọi thời đại. Quy luật sắp xếp sẽ dựa trên kiểu dữ liệu của tập hợp mà quyết định. Quan trọng là việc sắp xếp vẫn thực hiện trên chính tập hợp đó, nó sẽ thay đổi thứ tự các phần tử. Và nếu bạn áp dụng chọn const
thì sẽ gặp lỗi.
Xem ví dụ code nhoé!
final chars = ["X", "Z", "H", "O", "A", "B", "C", "D", "E"]; chars.sort(); print(chars); //[A, B, C, D, E, H, O, X, Z]
Ví dụ này cũng khá là đơn giản và không có gì phức tạp hết. Danh sách của bạn sẽ được làm lại một cách xinh đẹp với thứ tự sắp xếp theo chữ cái tăng dần.
Custom sort
Nếu bạn muốn áp dụng một quy luật khác, thì có thể sử dụng custom sort. Thực chất đây là bạn chọn tham số và tạo ra quy luật cho toán tử sort
ở trên mà thôi.
Xem ví dụ là hiểu liền.
final nums2 = [1, 9, -1, 22, 87, 57, 999, 246, 7, 0, 12]; nums2.sort((n1, n2) => n2.compareTo(n1)); print(nums2); //[999, 246, 87, 57, 22, 12, 9, 7, 1, 0, -1]
Trong đó:
- Điều kiện so sánh các phần tử là
n2.compareTo(n1)
, tạm thời bạn hiểu là chúng sắp xếp ngược
Nếu có điều kiện thì chúng ta sẽ tìm hiểu các tham số hay các cách để bạn thực hiện so sánh sau nhoé.
reversing
Bạn có cách đơn giản hơn để đão ngược lại danh sách của bạn. Đó chính là toán tử .reversed
. Thật là may mắn khi bạn có được một tập hợp mới sau khi gọi toán tử đó.
Xem ví dụ code nhoé!
final chartsReversed = chars.reversed; print(chars); // [A, B, C, D, E, H, O, X, Z] print(chartsReversed); (Z, X, O, H, E, D, C, B, A)
Kiểu dữ liệu cho tập hợp trả về bởi toán tử .reversed
là một kiểu Iterable.
combining
Cuối cùng, bạn có thể kết hợp nhiều toán tử the higher order methods với nhau. Tương tự như thế giới Rx hay Combine à. Kết quả của toán tử này là đầu vào của toán tử tiếp theo. Bạn sẽ gọi liên tiếp thông qua các dấu .
.
Xem ví dụ nhoé!
const desserts = ['cake', 'pie', 'donuts', 'brownies']; final bigTallDesserts = desserts .where((dessert) => dessert.length > 5) .map((dessert) => dessert.toUpperCase()); print(bigTallDesserts); //(DONUTS, BROWNIES)
Ta sẽ có một tập hợp cuối cùng thông qua 2 lần biến đổi với where
& map
. Tuy nhiên, bạn cần chú ý về kiểu dữ liệu của mỗi bước biến đổi. Điều này cực kì quan trọng.
Xem ví dụ sau, nếu bạn muốn đảo ngược danh sách kia, bằng cách thêm các toán tử reversed
nhoé.
final bigTallDesserts = desserts .where((dessert) => dessert.length > 5) .map((dessert) => dessert.toUpperCase()) .toList() .reversed;
Trước khi thực hiện reversed
thì chúng ta cần biến đổi Iterable về List. Vì reversed
không áp dụng cho kiểu Iterable được.
Tới đây, mình tạm thời kết thúc phần mệt mỏi này nhoé.
Tạm kết
- Tìm hiểu về các kiểu dữ liệu cấu trúc tập hợp trong Dart, là: List, Set, Map
- Các thuộc tính & phương thức cơ bản của chúng
- Các toán tử nâng cao cho các kiểu dữ liệu tập hợp này
- Kết hợp sử dụng các toán tử lại với nhau
Okay! Tới đây, mình xin kết thúc bài viết về Collections trong series Dart Tour. Nếu có gì thắc mắc hay góp ý cho mình thì bạn có thể để lại bình luận hoặc gởi email theo trang Contact.
Cảm ơn bạn đã đọc bài viết này!
Related Posts:
Written by chuotfx
Hãy ngồi xuống, uống miếng bánh và ăn miếng trà. Chúng ta cùng nhau đàm đạo về đời, về code nhóe!
Leave a Reply Cancel reply
Fan page
Tags
Recent Posts
- Charles Proxy – Phần 1 : Giới thiệu, cài đặt và cấu hình
- Complete Concurrency với Swift 6
- 300 Bài code thiếu nhi bằng Python – Ebook
- Builder Pattern trong 10 phút
- Observer Pattern trong 10 phút
- Memento Pattern trong 10 phút
- Strategy Pattern trong 10 phút
- Automatic Reference Counting (ARC) trong 10 phút
- Autoresizing Masks trong 10 phút
- Regular Expression (Regex) trong Swift
You may also like:
Archives
- September 2024 (1)
- July 2024 (1)
- June 2024 (1)
- May 2024 (4)
- April 2024 (2)
- March 2024 (5)
- January 2024 (4)
- February 2023 (1)
- January 2023 (2)
- November 2022 (2)
- October 2022 (1)
- September 2022 (5)
- August 2022 (6)
- July 2022 (7)
- June 2022 (8)
- May 2022 (5)
- April 2022 (1)
- March 2022 (3)
- February 2022 (5)
- January 2022 (4)
- December 2021 (6)
- November 2021 (8)
- October 2021 (8)
- September 2021 (8)
- August 2021 (8)
- July 2021 (9)
- June 2021 (8)
- May 2021 (7)
- April 2021 (11)
- March 2021 (12)
- February 2021 (3)
- January 2021 (3)
- December 2020 (3)
- November 2020 (9)
- October 2020 (7)
- September 2020 (17)
- August 2020 (1)
- July 2020 (3)
- June 2020 (1)
- May 2020 (2)
- April 2020 (3)
- March 2020 (20)
- February 2020 (5)
- January 2020 (2)
- December 2019 (12)
- November 2019 (12)
- October 2019 (19)
- September 2019 (17)
- August 2019 (10)