1. Giới thiệu
Trong nhiều ứng dụng, bạn có thể thấy dữ liệu được hiển thị dưới dạng danh sách: danh bạ, cài đặt, kết quả tìm kiếm, v.v.
Tuy nhiên, trong các mã bạn viết cho đến giờ, chủ yếu dành cho dữ liệu bao gồm một giá trị duy nhất, chẳng hạn như một số hoặc đoạn văn bản hiển thị trên màn hình. Để tạo ứng dụng liên quan đến lượng dữ liệu tùy ý, bạn cần tìm hiểu cách sử dụng bộ sưu tập.
Các kiểu bộ sưu tập (đôi khi được gọi là cấu trúc dữ liệu) cho phép bạn lưu trữ nhiều giá trị, thường là cùng một loại dữ liệu theo cách ngăn nắp. Bộ sưu tập có thể là một danh sách được sắp xếp theo thứ tự, một nhóm các giá trị duy nhất hoặc mối liên kết các giá trị của một loại dữ liệu tới các giá trị của loại khác. Khả năng sử dụng hiệu quả bộ sưu tập cho phép bạn triển khai các tính năng phổ biến của ứng dụng Android, chẳng hạn như danh sách cuộn, cũng như giải quyết nhiều vấn đề trong lập trình thực tế liên quan đến lượng dữ liệu tùy ý.
Lớp học lập trình này thảo luận về cách làm việc với nhiều giá trị trong mã của bạn đồng thời giới thiệu nhiều cấu trúc dữ liệu khác nhau, bao gồm mảng, danh sách, tập hợp và bản đồ.
Điều kiện tiên quyết
- Làm quen với lập trình hướng đối tượng trong Kotlin, bao gồm các lớp, giao diện và khái niệm chung.
Kiến thức bạn sẽ học được
- Cách tạo và sửa đổi mảng.
- Cách sử dụng
List
vàMutableList
. - Cách sử dụng
Set
vàMutableSet
. - Cách sử dụng
Map
vàMutableMap
.
Bạn cần có
- Một trình duyệt web có quyền truy cập vào Kotlin Playground.
2. Mảng trong Kotlin
Mảng là gì?
Mảng là cách đơn giản nhất để nhóm một số lượng giá trị tùy ý trong các chương trình của bạn.
Giống như một nhóm các bảng điều khiển năng lượng mặt trời được gọi là mảng năng lượng mặt trời, hoặc việc học chương trình Kotlin mở ra nhiều khả năng cho sự nghiệp lập trình của bạn, Array
đại diện cho nhiều giá trị. Cụ thể, mảng là một chuỗi các giá trị mà tất cả đều có cùng một loại dữ liệu.
- Một mảng chứa nhiều giá trị được gọi là phần tử hoặc đôi khi là các mục.
- Các phần tử trong một mảng được sắp xếp và truy cập bằng một chỉ mục.
Chỉ mục là gì? Chỉ mục là một số nguyên tương ứng với một phần tử trong mảng. Chỉ mục cho biết khoảng cách của một mục từ phần tử bắt đầu trong mảng. Hành động này được gọi là zero-indexing. Phần tử đầu tiên của mảng nằm ở chỉ mục 0, phần tử thứ hai ở chỉ mục 1, vì nó cách phần tử đầu tiên một vị trí, và cứ thế tiếp tục.
Trong bộ nhớ của thiết bị, các phần tử trong mảng được lưu trữ cạnh nhau. Mặc dù các chi tiết cơ bản nằm ngoài phạm vi của lớp học lập trình này nhưng đều có hai ý nghĩa quan trọng:
- Quyền truy cập vào một phần tử mảng theo chỉ mục của phần tử này rất nhanh. Bạn có quyền truy cập vào bất kỳ phần tử ngẫu nhiên nào trong một mảng theo chỉ mục của nó và dự kiến sẽ mất cùng một khoảng thời gian để truy cập bất kỳ phần tử ngẫu nhiên nào khác. Đây là lý do vì sao các mảng được cho là có quyền truy cập ngẫu nhiên.
- Một mảng thường có kích thước cố định. Điều này có nghĩa là bạn không thể thêm các phần tử vào một mảng vượt quá kích thước này. Việc cố gắng truy cập vào phần tử ở chỉ mục 100 trong một mảng gồm 100 phần tử sẽ tạo một ngoại lệ vì chỉ mục cao nhất là 99 (vui lòng lưu ý chỉ mục đầu tiên là 0 thay vì 1). Tuy nhiên, bạn có thể sửa đổi các giá trị tại chỉ mục trong mảng.
Để khai báo một mảng trong mã, bạn cần dùng hàm arrayOf()
.
Hàm arrayOf()
lấy các phần tử mảng ở dạng tham số và trả về một mảng thuộc loại khớp với các tham số đã được truyền vào. Việc này có thể trông hơi khác so với các hàm khác mà bạn thấy vì arrayOf()
có nhiều tham số khác nhau. Nếu bạn truyền hai đối số vào arrayOf()
, mảng kết quả sẽ chứa hai phần tử, được lập chỉ mục 0 và 1. Nếu bạn truyền ba đối số, mảng thu được sẽ có 3 phần tử, được lập chỉ mục từ 0 đến 2.
Hãy xem các mảng hoạt động qua khám phá nhỏ về hệ mặt trời!
- Chuyển đến phần Kotlin Playground.
- Trong
main()
, hãy tạo một biếnrockPlanets
. GọiarrayOf()
, truyền theo loạiString
, cùng với 4 chuỗi — một chuỗi cho mỗi hành tinh đá trong hệ mặt trời.
val rockPlanets = arrayOf<String>("Mercury", "Venus", "Earth", "Mars")
- Vì Kotlin sử dụng cách dự đoán theo loại, nên bạn có thể bỏ qua tên loại khi gọi
arrayOf()
. Bên dưới biếnrockPlanets
, hãy thêm một biến khácgasPlanets
mà không cần truyền một loại vào trong dấu ngoặc nhọn.
val gasPlanets = arrayOf("Jupiter", "Saturn", "Uranus", "Neptune")
- Bạn sẽ thấy các mảng thú vị thế nào khi khám phá. Ví dụ: tương tự như loại số
Int
hoặcDouble
, bạn có thể thêm hai mảng với nhau. Tạo một biến mới có tên làsolarSystem
và đặt biến đó bằng kết quả củarockPlanets
vàgasPlanets
, sử dụng toán tử dấu cộng (+
). Kết quả là một mảng mới chứa tất cả các phần tử của mảngrockPlanets
vàgasPlanets
.
val solarSystem = rockPlanets + gasPlanets
- Chạy chương trình để xác minh nó hoạt động đúng cách. Bạn chưa thấy dữ liệu đầu ra nào.
Truy cập phần tử trong một mảng
Bạn có thể truy cập vào phần tử của một mảng theo chỉ mục của mảng đó.
Đây được gọi là cú pháp chỉ số dưới. Nó bao gồm ba phần:
- Tên mảng.
- Dấu ngoặc vuông mở (
[
) và đóng (]
). - Chỉ mục của phần tử mảng trong dấu ngoặc vuông.
Vui lòng truy cập vào các phần tử của mảng solarSystem
theo chỉ mục của chúng.
- Trong
main()
, hãy truy cập và in từng phần tử của mảngsolarSystem
. Vui lòng lưu ý chỉ mục đầu tiên là0
và chỉ mục cuối cùng là7
.
println(solarSystem[0])
println(solarSystem[1])
println(solarSystem[2])
println(solarSystem[3])
println(solarSystem[4])
println(solarSystem[5])
println(solarSystem[6])
println(solarSystem[7])
- Chạy chương trình. Các phần tử phải theo đúng thứ tự mà bạn đã liệt kê khi gọi
arrayOf()
.
Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune
Bạn cũng có thể đặt giá trị của một phần tử mảng theo chỉ mục của nó.
Cách truy cập vào chỉ mục cũng tương tự như trước đây — nghĩa là tên của mảng, theo sau là dấu ngoặc vuông mở và đóng chứa chỉ mục. Tiếp theo là toán tử chỉ định (=
) và một giá trị mới.
Hãy thực hành sửa đổi các giá trị trên mảng solarSystem
.
- Hãy đặt một tên mới cho sao Hỏa phục vụ những người định cư trong tương lai. Truy cập phần tử tại chỉ mục
3
và đặt phần tử này bằng"Little Earth"
.
solarSystem[3] = "Little Earth"
- In phần tử tại chỉ mục
3
.
println(solarSystem[3])
- Chạy chương trình. Phần tử thứ tư của mảng (tại chỉ mục
3
) đã được cập nhật.
... Little Earth
- Bây giờ, giả sử các nhà khoa học đã khám phá ra có một hành tinh thứ 9 nằm bên ngoài Neptune với tên gọi Pluto. Trước đó, chúng tôi đã đề cập việc không thể đổi kích thước mảng. Điều gì sẽ xảy ra nếu bạn thử thay đổi các kích thước mảng đó? Hãy thử thêm Pluto vào mảng
solarSystem
. Thêm Pluto tại chỉ mục8
vì đây là phần tử thứ 9 trong mảng.
solarSystem[8] = "Pluto"
- Chạy mã. Thao tác này sẽ tạo một trường hợp ngoại lệ
ArrayIndexOutOfBounds
. Vì mảng đã có 8 phần tử như dự kiến, nên bạn không thể chỉ thêm một phần tử thứ chín.
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 8 out of bounds for length 8
- Xóa Pluto đã thêm vào mảng.
Mã cần xóa
solarSystem[8] = "Pluto"
- Nếu sửa một mảng lớn hơn kích thước có sẵn, bạn cần phải tạo một mảng mới. Xác định một biến mới có tên là
newSolarSystem
như minh họa. Mảng này có thể lưu trữ 9 thay vì 8 phần tử.
val newSolarSystem = arrayOf("Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune", "Pluto")
- Bây giờ, hãy thử in phần tử tại chỉ mục
8
.
println(newSolarSystem[8])
- Chạy mã của bạn và quan sát xem liệu mã đó có chạy mà không tạo bất kỳ ngoại lệ nào không.
... Pluto
Tuyệt vời! Với kiến thức hiện có về mảng, bạn có thể thỏa thích khám phá hầu hết mọi thứ về bộ sưu tập.
Đợi đã, thực sự không dễ dàng vậy đâu! Mặc dù mảng là một trong các thành phần cơ bản của lập trình, nhưng việc sử dụng mảng cho các tác vụ có yêu cầu thêm và xóa các phần tử, tính duy nhất trong một bộ sưu tập hoặc việc ánh xạ một đối tượng đến các đối tượng khác không hề đơn giản hoặc dễ hiểu khiến mã của ứng dụng sẽ nhanh chóng trở nên lộn xộn.
Đây là lý do hầu hết các ngôn ngữ lập trình, kể cả Kotlin, đều triển khai các loại bộ sưu tập đặc biệt để xử lý các tình huống thường xảy ra trong ứng dụng thực tế. Trong các phần sau, bạn sẽ tìm hiểu về ba bộ sưu tập phổ biến: List
, Set
và Map
. Bạn cũng sẽ tìm hiểu về các thuộc tính và phương thức phổ biến cũng như các trường hợp sử dụng các loại bộ sưu tập này.
3. Danh sách
Danh sách là một tập hợp có thể thay đổi kích thước, được sắp xếp theo thứ tự, thường được triển khai dưới dạng một mảng có thể thay đổi kích thước. Khi mảng đã đạt hạn mức nhưng bạn cố gắng chèn thêm một phần tử mới, mảng sẽ được sao chép vào một mảng mới lớn hơn.
Với danh sách, bạn cũng có thể chèn các phần tử mới giữa các phần tử khác vào một chỉ mục cụ thể.
Đây là cách các danh sách có thể thêm và xóa phần tử. Trong hầu hết các trường hợp, việc thêm bất kỳ phần tử nào vào danh sách cũng đều cần cùng một khoảng thời gian, bất kể có bao nhiêu phần tử trong danh sách. Đôi khi, nếu việc thêm một phần tử mới khiến mảng vượt quá kích thước đã xác định, thì các phần tử mảng có thể phải di chuyển để tạo chỗ trống cho các phần tử mới. Tính năng danh sách sẽ làm tất cả những điều này cho bạn, nhưng trên thực tế, việc này chỉ đơn giản là một mảng được hoán đổi cho một mảng mới khi cần.
List
và MutableList
Các loại bộ sưu tập mà bạn sẽ gặp trong Kotlin khi triển khai một hoặc nhiều giao diện. Như chúng ta đã tìm hiểu ở lớp học lập trình trước đó trong chương này về Các thành phần chung, đối tượng và tiện ích, giao diện cung cấp một tập hợp các thuộc tính và phương thức chuẩn cho một lớp để triển khai. Một lớp triển khai giao diện List
cung cấp các phương thức triển khai cho tất cả các thuộc tính và phương thức của giao diện List
. Điều này cũng đúng đối với MutableList
.
Vậy List
và MutableList
có chức năng gì?
List
là một giao diện xác định các thuộc tính và phương thức liên quan đến một tập hợp các mục chỉ có thể đọc theo thứ tự.MutableList
mở rộng giao diệnList
bằng cách xác định các phương thức sửa đổi danh sách, chẳng hạn như thêm và xóa phần tử.
Các giao diện này chỉ chỉ định các thuộc tính và phương thức của List
và/hoặc MutableList
. Nó tùy thuộc vào lớp mở rộng để xác định cách triển khai từng thuộc tính cũng như phương thức. Việc triển khai dựa trên mảng được mô tả ở trên là cách bạn sẽ sử dụng nhiều nhất (nếu không phải lúc nào cũng được), nhưng Kotlin cho phép các lớp khác mở rộng List
và MutableList
.
Hàm listOf()
Tương tự như arrayOf()
, hàm listOf()
lấy các mục dưới dạng tham số, nhưng trả về List
thay vì một mảng.
- Xóa mã hiện có khỏi
main()
. - Trong
main()
, hãy tạo mộtList
các hành tinh có tên làsolarSystem
bằng cách gọilistOf()
.
fun main() {
val solarSystem = listOf("Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune")
}
List
chứa thuộc tínhsize
để nhận số phần tử trong danh sách. Insize
của danh sáchsolarSystem
.
println(solarSystem.size)
- Chạy mã. Kích thước của danh sách phải là 8.
8
Truy cập các phần tử trong một danh sách
Tương tự như mảng, bạn có thể truy cập vào phần tử trong một chỉ mục cụ thể từ một List
bằng cú pháp chỉ số dưới. Bạn có thể thực hiện tương tự với phương thức get()
. Cú pháp chỉ số dưới và phương thức get()
lấy Int
làm tham số và trả về phần tử ở chỉ mục đó. Tương tự như Array
, ArrayList
không được lập chỉ mục. Do đó, phần tử thứ tư sẽ nằm trong chỉ mục 3
, chẳng hạn như vậy.
- In hành tinh tại chỉ mục
2
bằng cú pháp chỉ số dưới.
println(solarSystem[2])
- In phần tử tại chỉ mục
3
bằng cách gọiget()
trên danh sáchsolarSystem
.
println(solarSystem.get(3))
- Chạy mã. Phần tử ở chỉ mục
2
là"Earth"
và phần tử ở chỉ mục3
là"Mars"
.
... Earth Mars
Ngoài việc lấy một phần tử theo chỉ mục của nó, bạn cũng có thể tìm kiếm chỉ mục của một phần tử cụ thể bằng phương thức indexOf()
. Phương thức indexOf()
tìm kiếm danh sách cho một phần tử nhất định (được truyền dưới dạng đối số) và trả về chỉ mục trong lần xuất hiện đầu tiên của phần tử đó. Nếu không có phần tử nào trong danh sách, chỉ số được trả về sẽ là -1
.
- In kết quả gọi
indexOf()
trên danh sáchsolarSystem
, truyền qua"Earth"
.
println(solarSystem.indexOf("Earth"))
- Gọi
indexOf()
, truyền qua"Pluto"
và in kết quả.
println(solarSystem.indexOf("Pluto"))
- Chạy mã. Phần tử khớp với
"Earth"
, do đó, chỉ mục2
sẽ được in. Không có phần tử nào khớp với"Pluto"
, vì vậy,-1
sẽ được in.
... 2 -1
Lặp lại các phần tử danh sách bằng cách sử dụng vòng lặp for
Khi tìm hiểu về các loại hàm và biểu thức lambda, bạn đã biết cách dùng hàm repeat()
để thực thi mã nhiều lần.
Nhiệm vụ phổ biến trong lập trình là thực hiện nhiệm vụ một lần cho từng phần tử trong một danh sách. Kotlin có một tính năng gọi là vòng lặp for
để thực hiện điều này bằng cú pháp ngắn gọn và dễ đọc. Thông thường bạn sẽ thấy hoạt động này được gọi là lặp lại theo một danh sách hoặc vòng lặp qua một danh sách.
Để lặp lại theo một danh sách, hãy sử dụng từ khóa for
, theo sau là một cặp dấu ngoặc mở và đóng. Trong dấu ngoặc đơn, hãy thêm tên biến, theo sau là từ khóa in
, tiếp đến là tên bộ sưu tập. Sau dấu ngoặc đơn đóng sẽ là một cặp dấu ngoặc nhọn mở và đóng, trong đó bạn phải thêm mã mình muốn thực thi cho từng phần tử trong bộ sưu tập. Nó được gọi là phần nội dung của vòng lặp. Mỗi lần mã này thực thi được gọi là một vòng lặp.
Không khai báo biến trước từ khóa in
bằng val
hoặc var
– nó được coi là những giá trị chỉ nhận. Bạn có thể đặt bất kỳ tên nào bạn muốn. Nếu một danh sách có tên là số nhiều, chẳng hạn như planets
, thì thông thường bạn nên đặt tên cho biến có dạng số ít, chẳng hạn như planet
. Bạn cũng nên đặt tên cho biến item
hoặc element
.
Biến này sẽ được dùng làm biến tạm thời tương ứng với phần tử hiện tại trong bộ sưu tập – phần tử tại chỉ mục 0
cho lần lặp đầu tiên, phần tử ở chỉ mục 1
cho lần lặp thứ hai, v.v. và có thể truy cập được trong dấu ngoặc nhọn.
Để thực hiện được việc này, bạn sẽ in mỗi tên hành tinh trên một dòng riêng bằng cách sử dụng vòng lặp for
.
- Trong
main()
, bên dưới cuộc gọi gần đây nhất đếnprintln()
, hãy thêm một vòng lặpfor
. Trong dấu ngoặc đơn, hãy đặt tên cho biếnplanet
và lặp qua danh sáchsolarSystem
.
for (planet in solarSystem) {
}
- Trong dấu ngoặc nhọn, hãy in giá trị của
planet
bằngprintln()
.
for (planet in solarSystem) {
println(planet)
}
- Chạy mã. Mã trong phần nội dung của vòng lặp được thực thi cho từng mục trong bộ sưu tập.
... Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune
Thêm phần tử vào danh sách
Khả năng thêm, xóa và cập nhật các phần tử trong một bộ sưu tập chỉ dành cho các lớp triển khai giao diện MutableList
. Nếu đang theo dõi các hành tinh mới được phát hiện, bạn có thể sẽ muốn thêm được các phần tử vào danh sách một cách thường xuyên. Khi cần tạo danh sách mà bạn muốn thêm và xóa các phần tử, bạn phải gọi hàm mutableListOf()
cụ thể thay vì listOf()
.
Có hai phiên bản của hàm add()
:
- Hàm
add()
đầu tiên có một tham số thuộc loại phần tử trong danh sách và thêm tham số đó vào cuối danh sách. - Phiên bản khác của
add()
có hai tham số. Tham số đầu tiên tương ứng với một chỉ mục mà phần tử mới sẽ được chèn vào đó. Tham số thứ hai là phần tử đang được thêm vào danh sách.
Vui lòng xem ví dụ thực tế.
- Thay đổi cách khởi chạy
solarSystem
để gọimutableListOf()
thay vìlistOf()
. Giờ đây, bạn có thể gọi các phương thức được xác định trongMutableList
.
val solarSystem = mutableListOf("Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune")
- Chúng ta có thể lại muốn phân loại Pluto là một hành tinh. Gọi phương thức
add()
trênsolarSystem
, truyền"Pluto"
vào để làm đối số duy nhất.
solarSystem.add("Pluto")
- Một số nhà khoa học đưa ra giả thuyết về một hành tinh có tên Theia từng tồn tại trước khi va chạm với Trái đất và hình thành Mặt trăng. Chèn
"Theia"
ở chỉ mục3
, giữa"Earth"
và"Mars"
.
solarSystem.add(3, "Theia")
Cập nhật các thành phần tại một chỉ mục cụ thể
Bạn có thể cập nhật các phần tử hiện có bằng cú pháp chỉ số dưới:
- Cập nhật giá trị tại chỉ mục
3
thành"Future Moon"
.
solarSystem[3] = "Future Moon"
- In giá trị tại chỉ mục
3
và9
bằng cú pháp chỉ số dưới.
println(solarSystem[3])
println(solarSystem[9])
- Chạy mã của bạn để xác minh kết quả.
Future Moon Pluto
Xóa phần tử khỏi danh sách
Các phần tử sẽ bị xóa bằng phương thức remove()
hoặc removeAt()
. Bạn có thể xóa một phần tử bằng cách truyền phần tử đó vào phương thức remove()
hoặc bằng chỉ mục của phần tử đó bằng cách sử dụng removeAt()
.
Hãy xem cả hai phương pháp xóa phần tử trong thực tế.
- Gọi
removeAt()
trênsolarSystem
, truyền9
vào chỉ mục. Thao tác này sẽ xóa"Pluto"
khỏi danh sách.
solarSystem.removeAt(9)
- Gọi
remove()
trênsolarSystem
, truyền"Future Moon"
vào dưới dạng phần tử để xóa. Phương thức này sẽ tìm kiếm trong danh sách và nếu tìm thấy phần tử phù hợp, phần tử này sẽ bị xóa.
solarSystem.remove("Future Moon")
List
cung cấp phương thứccontains()
trả vềBoolean
nếu một phần tử tồn tại trong danh sách. In kết quả gọicontains()
cho"Pluto"
.
println(solarSystem.contains("Pluto"))
- Còn một cú pháp ngắn gọn hơn nữa là sử dụng toán tử
in
. Bạn có thể kiểm tra xem một phần tử có trong danh sách hay không bằng cách sử dụng phần tử, toán tửin
và bộ sưu tập. Dùng toán tửin
để kiểm tra xemsolarSystem
có chứa"Future Moon"
không.
println("Future Moon" in solarSystem)
- Chạy mã. Cả hai câu lệnh đều phải in
false
.
... false false
4. Tập hợp
Tập hợp là một bộ sưu tập không có thứ tự cụ thể và không chấp nhận các giá trị trùng lặp.
Làm thế nào để tạo một bộ sưu tập tương tự như thế này? Mã băm là một bí . Mã băm là một Int
do phương thức hashCode()
của bất kỳ lớp Kotlin nào tạo ra. Bạn có thể coi mã này là giá trị nhận dạng gần như duy nhất cho một đối tượng Kotlin. Một thay đổi nhỏ đối với đối tượng, chẳng hạn như việc thêm ký tự vào String
sẽ dẫn đến một giá trị băm khác biệt lớn. Mặc dù hai đối tượng có thể có cùng một mã băm (được gọi là xung đột hàm băm), nhưng hàm hashCode()
đảm bảo mức độ riêng biệt nào đó trong hầu hết các trường hợp, nơi hai giá trị khác nhau, mỗi giá trị có một mã băm duy nhất.
Tập hợp có hai thuộc tính quan trọng:
- Việc tìm kiếm một phần tử cụ thể trong tập hợp diễn ra nhanh chóng so với danh sách – đặc biệt là đối với các bộ sưu tập lớn. Mặc dù
indexOf()
củaList
yêu cầu kiểm tra từng phần tử ban đầu cho đến khi tìm thấy kết quả trùng khớp, nhưng tựu chung cũng mất khoảng thời gian tương tự để kiểm tra xem một phần tử có nằm trong tập hợp hay không, cho dù đó có là phần tử đầu tiên hay phần tử thứ trăm nghìn. - Tập hợp có xu hướng sử dụng nhiều bộ nhớ hơn so với danh sách cho cùng một lượng dữ liệu, vì tập hợp thường cần nhiều chỉ mục mảng hơn là dữ liệu.
Lợi ích của tập hợp là đảm bảo tính duy nhất. Nếu bạn đang viết một chương trình để theo dõi các hành tinh mới được khám phá, thì tập hợp sẽ cung cấp cách đơn giản để kiểm tra xem một hành tinh đã được khám phá hay chưa. Với một lượng lớn dữ liệu, tốt hơn là bạn nên kiểm tra xem phần tử có tồn tại trong danh sách hay không, điều này đòi hỏi việc sử dụng vòng lặp qua tất cả các phần tử.
Giống như List
và MutableList
, có cả Set
và MutableSet
. MutableSet
triển khai Set
, vì vậy, bất kỳ lớp nào triển khai MutableSet
cũng đều cần triển khai cả hai.
Sử dụng MutableSet
trong Kotlin
Chúng ta sẽ dùng MutableSet
trong ví dụ để minh họa cách thêm và xóa các phần tử.
- Xóa mã hiện có khỏi
main()
. - Tạo
Set
hành tinh có tên làsolarSystem
bằngmutableSetOf()
. URL này trả vềMutableSet
, cách triển khai mặc định làLinkedHashSet()
.
val solarSystem = mutableSetOf("Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune")
- In kích thước của tập hợp bằng cách sử dụng thuộc tính
size
.
println(solarSystem.size)
- Giống như
List
,Set
có một phương thứcadd()
. Thêm"Pluto"
vào tập hợpsolarSystem
bằng phương thứcadd()
. Chỉ cần một tham số duy nhất cho phần tử đang được thêm. Các phần tử trong tập hợp không nhất thiết phải có thứ tự, do đó không có chỉ mục!
solarSystem.add("Pluto")
- In
size
của tập hợp sau khi thêm phần tử.
println(solarSystem.size)
- Hàm
contains()
nhận một tham số duy nhất và kiểm tra xem liệu phần tử được chỉ định có nằm trong tập hợp hay không. Nếu có, kết quả sẽ trả về là true. Nếu không, hàm này sẽ trả về giá trị "false". Gọicontains()
để kiểm tra xem"Pluto"
có trongsolarSystem
không.
println(solarSystem.contains("Pluto"))
- Chạy mã. Kích thước đã tăng và
contains()
hiện trả vềtrue
.
8 9 true
- Như đã đề cập trước đó, các tập hợp không được chứa bản sao. Hãy thử thêm lại
"Pluto"
.
solarSystem.add("Pluto")
- In lại kích thước của tập hợp.
println(solarSystem.size)
- Chạy lại mã.
"Pluto"
không được thêm vào vì đã có trong tập hợp. Lần này, bạn không phải tăng kích thước.
... 9
Hàm remove()
nhận một tham số duy nhất và xóa phần tử được chỉ định khỏi tập hợp.
- Dùng hàm
remove()
để xóa"Pluto"
.
solarSystem.remove("Pluto")
- In kích thước của bộ sưu tập và gọi lại
contains()
để kiểm tra xem"Pluto"
có còn trong tập hợp hay không.
println(solarSystem.size)
println(solarSystem.contains("Pluto"))
- Chạy mã.
"Pluto"
không còn nằm trong tập hợp và kích thước hiện tại là 8.
... 8 false
5. Thu thập bản đồ
Map
là một tập hợp bao gồm các khóa và giá trị. Đây được gọi là bản đồ vì các khóa duy nhất được ánh xạ với các giá trị khác. Khóa và giá trị đi kèm thường được gọi là key-value pair
.
Các khóa của bản đồ có giá trị duy nhất. Tuy nhiên, giá trị của bản đồ thì không. Hai khóa khác nhau có thể ánh xạ đến cùng một giá trị. Ví dụ: "Mercury"
có 0
mặt trăng và "Venus"
có 0
mặt trăng.
Thông thường, tốc độ truy cập giá trị từ một bản đồ bằng khóa của bản đồ đó nhanh hơn so với việc tìm kiếm thông qua một danh sách lớn, chẳng hạn như bằng indexOf()
.
Bạn có thể khai báo Maps bằng hàm mapOf()
hoặc mutableMapOf()
. Maps yêu cầu hai loại chung chung được phân tách bằng dấu phẩy – một loại cho khóa và một loại cho giá trị.
Một bản đồ cũng có thể sử dụng dự đoán loại nếu bản đồ có các giá trị ban đầu. Để điền một bản đồ có các giá trị ban đầu, mỗi cặp giá trị khóa bao gồm khóa, theo sau là toán tử to
, tiếp đến là giá trị. Mỗi cặp được phân tách bằng dấu phẩy.
Hãy cùng tìm hiểu cách sử dụng bản đồ cũng như một số thuộc tính và phương pháp hữu ích.
- Xóa mã hiện có khỏi
main()
. - Tạo bản đồ có tên là
solarSystem
bằng cách sử dụngmutableMapOf()
với các giá trị ban đầu như được hiển thị.
val solarSystem = mutableMapOf(
"Mercury" to 0,
"Venus" to 0,
"Earth" to 1,
"Mars" to 2,
"Jupiter" to 79,
"Saturn" to 82,
"Uranus" to 27,
"Neptune" to 14
)
- Giống như danh sách và tập hợp,
Map
cung cấp thuộc tínhsize
, chứa số lượng cặp khóa-giá trị. In kích thước của bản đồsolarSystem
.
println(solarSystem.size)
- Bạn có thể sử dụng cú pháp chỉ số dưới để đặt các cặp khóa-giá trị bổ sung. Đặt khóa
"Pluto"
thành giá trị5
.
solarSystem["Pluto"] = 5
- In lại kích thước sau khi chèn phần tử.
println(solarSystem.size)
- Bạn có thể sử dụng cú pháp chỉ số dưới để nhận giá trị. In số mặt trăng cho khóa
"Pluto"
.
println(solarSystem["Pluto"])
- Bạn cũng có thể truy cập các giá trị bằng phương thức
get()
. Cho dù bạn sử dụng cú pháp chỉ số dưới hay gọiget()
, thì có thể khóa bạn truyền không có trong bản đồ. Nếu không có cặp khóa-giá trị thì hàm sẽ trả về giá trị null. In số mặt trăng cho"Theia"
.
println(solarSystem["Theia"])
- Chạy mã. Số mặt trăng của Pluto sẽ được in. Tuy nhiên, vì Theia không có trong bản đồ, nên việc gọi
get()
sẽ trả về giá trị null.
8 9 5 null
Phương thức remove()
sẽ xóa cặp khóa-giá trị bằng khóa được chỉ định. Thao tác này cũng trả về giá trị đã xóa, hoặc null
, nếu khóa được chỉ định không có trong bản đồ.
- In kết quả bằng cách gọi
remove()
và truyền vào"Pluto"
.
solarSystem.remove("Pluto")
- Để xác minh mục đã bị xóa, hãy in lại kích thước.
println(solarSystem.size)
- Chạy mã. Kích thước của bản đồ là 8 sau khi xóa mục nhập.
... 8
- Cú pháp chỉ số dưới hoặc phương thức
put()
cũng có thể sửa đổi giá trị cho khóa đã tồn tại. Sử dụng cú pháp chỉ số dưới để cập nhật các mặt trăng của sao Mộc thành 78 và in giá trị mới.
solarSystem["Jupiter"] = 78
println(solarSystem["Jupiter"])
- Chạy mã. Giá trị của khóa hiện tại
"Jupiter"
đã được cập nhật.
... 78
6. Kết luận
Xin chúc mừng! Bạn đã tìm hiểu về một trong các loại dữ liệu cơ bản nhất trong lập trình, mảng và một số loại bộ sưu tập tiện lợi được xây dựng từ các mảng, bao gồm List
, Set
và Map
. Các loại bộ sưu tập này cho phép bạn nhóm và sắp xếp giá trị trong mã của mình. Mảng và danh sách cho phép bạn truy cập nhanh vào các phần tử theo chỉ mục của chúng, trong khi tập hợp và bản đồ sử dụng mã băm để giúp bạn dễ dàng tìm thấy các phần tử trong bộ sưu tập hơn. Bạn sẽ thấy các loại bộ sưu tập này được sử dụng thường xuyên ở các ứng dụng trong tương lai, đồng thời việc biết cách sử dụng những bộ sưu tập này sẽ mang lại lợi ích cho bạn trong sự nghiệp lập trình sau này của mình.
Tóm tắt
- Mảng lưu trữ dữ liệu được sắp xếp theo cùng một loại và có kích thước cố định.
- Mảng được dùng để triển khai nhiều loại bộ sưu tập khác.
- Danh sách là một bộ sưu tập có thứ tự và thay đổi kích thước.
- Tập hợp là bộ sưu tập không theo thứ tự và không thể chứa các bản sao.
- Maps hoạt động tương tự như tập hợp đồng thời lưu trữ các cặp khóa và giá trị thuộc loại đã chỉ định.