Trong phần này chúng ta sẽ học về một số lớp dùng để lưu trữ dữ liệu trong Qt 5. Đó là các lớp QVector
, QList
, QStringList
, QSet
, và QMap
.
Trong thư viện chuẩn của C++ là Standard Template Library (STL) cũng có một số lớp có chức năng tương tự. Bạn có thể dùng các lớp đó hoặc các lớp mình sắp nói dưới đây, cái nào cũng tốt cả.
Các lớp này được chia làm hai loại, loại thứ nhất lưu dữ liệu theo kiểu danh sách, loại thứ hai lưu theo kiểu các cặp khóa-giá trị (key-value). QList
, QVector
, QLinkedList
là các lớp lưu theo kiểu danh sách; còn QMap
và QHash
lưu theo kiểu cặp khóa-giá trị.
QVector
QVector
lưu trữ dữ liệu theo kiểu danh sách. Các phần tử trong QVector
nằm kế tiếp nhau trong bộ nhớ và có thể truy cập thông qua chỉ số nên có tốc độ truy xuất dữ liệu rất nhanh nếu số lượng phần tử không nhiều. Nếu dữ liệu cần lưu trữ quá lớn thì tốt nhất là bạn nên dùng QList
thay thế.
#include <QVector> #include <QTextStream> int main(void) { QTextStream out(stdout); QVector<int> vals = {1, 2, 3, 4, 5}; out << "The size of the vector is: " << vals.size() << endl; out << "The first item is: " << vals.first() << endl; out << "The last item is: " << vals.last() << endl; vals.append(6); vals.prepend(0); out << "Elements: "; for (int val : vals) { out << val << " "; } out << endl; return 0; }
Ví dụ trên tạo ra một vector lưu trữ các số nguyên.
QVector<int> vals = {1, 2, 3, 4, 5};
Khởi tạo vector
out << "The size of the vector is: " << vals.size() << endl;
Phương thức size()
trả về kích thước của vector – số lượng các phần tử có trong vector.
out << "The first item is: " << vals.first() << endl;
Truy xuất phần tử đầu tiên với phương thức first()
.
out << "The last item is: " << vals.last() << endl;
Truy xuất phần tử cuối cùng với phương thức last()
.
vals.append(6);
Phương thức append()
chèn một phần tử vào sau vector.
vals.prepend(0);
Phương thức prepend()
chèn một phần tử vào đầu vector.
for (int val : vals) { out << val << " "; }
Chúng ta duyệt qua vector và in các phần tử ra màn hình.
The size of the vector is: 5 The first item is: 1 The last item is: 5 Elements: 0 1 2 3 4 5 6
QList
QList
cũng có chức năng tương tự như QVector
. Nó cũng lưu trữ dữ liệu theo kiểu danh sách và truy xuất các phần tử thông qua chỉ số, nhưng tốc độ chèn và xóa dữ liệu nhanh hơn QVector.
Đây là một trong những lớp hay dùng nhất trong Qt
#include <QTextStream> #include <QList> #include <algorithm> int main(void) { QTextStream out(stdout); QList<QString> authors = {"Balzac", "Tolstoy", "Gulbranssen", "London"}; for (int i=0; i < authors.size(); ++i) { out << authors.at(i) << endl; } authors << "Galsworthy" << "Sienkiewicz"; out << "***********************" << endl; std::sort(authors.begin(), authors.end()); out << "Sorted:" << endl; for (QString author : authors) { out << author << endl; } }
Ví dụ cách sử dụng QList
.
QList<QString> authors = {"Balzac", "Tolstoy", "Gulbranssen", "London"};
Khởi tạo QList
là danh sách tên các nhà văn.
for (int i=0; i < authors.size(); ++i) { out << authors.at(i) << endl; }
Ta duyệt qua QList
bằng vòng lặp for và in dữ liệu ra màn hình bằng phương thức at()
. Phương thức này nhận tham số đầu vào là chỉ số phần tử.
authors << "Galsworthy" << "Sienkiewicz";
Dùng toán tử << để chèn một phần tử mới vào sau QList.
std::sort(authors.begin(), authors.end());
Phương thức std::sort()
sắp xếp các phần tử trong QList
.
out << "Sorted:" << endl; for (QString author : authors) { out << author << endl; }
In ra danh sách đã được sắp xếp.
Balzac Tolstoy Gulbranssen London *********************** Sorted: Balzac Galsworthy Gulbranssen London Sienkiewicz Tolstoy
QStringList
QStringList
cũng giống như QList
nhưng chuyên để làm việc với string.
#include <QTextStream> #include <QList> int main(void) { QTextStream out(stdout); QString string = "coin, book, cup, pencil, clock, bookmark"; QStringList items = string.split(","); QStringListIterator it(items); while (it.hasNext()) { out << it.next().trimmed() << endl; } }
Ví dụ trên tạo ra một danh sách các string và in các phần tử trong danh sách ra màn hình.
QString string = "coin, book, cup, pencil, clock, bookmark"; QStringList items = string.split(",");
Phương thức split()
tách một chuỗi thành nhiều chuỗi con dựa vào dấu phân tách mà ta đưa vào.
QStringListIterator it(items);
QStringListIterator
là một lớp chuyên dùng để thao tác với QStringList.
while (it.hasNext()) { out << it.next().trimmed() << endl; }
Sau khi đã khởi tạo iterator, chúng ta in từng phần tử ra màn hình. Phương thức trimmed()
sẽ xóa các khoảng trống thừa trong chuỗi.
coin book cup pencil clock bookmark
QSet
QSet
lưu trữ các phần tử dữ liệu đơn lẻ. Các phần tử trong QSet
không được lưu theo một thứ tự nào cả.
#include <QSet> #include <QList> #include <QTextStream> #include <algorithm> int main(void) { QTextStream out(stdout); QSet<QString> cols1 = {"yellow", "red", "blue"}; QSet<QString> cols2 = {"blue", "pink", "orange"}; out << "There are " << cols1.size() << " values in the set" << endl; cols1.insert("brown"); out << "There are " << cols1.size() << " values in the set" << endl; cols1.unite(cols2); out << "There are " << cols1.size() << " values in the set" << endl; for (QString val : cols1) { out << val << endl; } QList<QString> lcols = cols1.values(); std::sort(lcols.begin(), lcols.end()); out << "*********************" << endl; out << "Sorted:" << endl; for (QString val : lcols) { out << val << endl; } return 0; }
Ví dụ trên tạo ra các QSet
lưu tên của các màu. Không có phần tử nào xuất hiện hai lần trở lên – tức là giá trị của mỗi phần tử là khác nhau.
QSet<QString> cols1 = {"yellow", "red", "blue"}; QSet<QString> cols2 = {"blue", "pink", "orange"};
Chúng ta có hai tập dữ liệu, hai tập này chứa một phần tử chung là “blue”.
out << "There are " << cols1.size() << " values in the set" << endl;
Phương thức size()
trả về kích thước của tập.
cols1.insert("brown");
Chúng ta thêm một phần tử mới vào tập bằng phương thức insert()
.
cols1.unite(cols2);
Phương thức unite()
thực hiện phép hợp hai tập này. Tập cols1
sẽ thêm vào các phần tử có trong tập cols2
mà chưa có trong tập cols1
, mà ở đây chính là phần tử “blue”.
for (QString val : cols1) { out << val << endl; }
Ta dùng vòng lặp for để in các phần tử ra của tập cols1
màn hình.
QList<QString> lcols = cols1.values(); std::sort(lcols.begin(), lcols.end());
Chúng ta không thể sắp xếp một tập hợp. Nếu cần bạn có thể tạo ra một QList
rồi sắp xếp, phương thức values()
sẽ trả về một QList
chứa các phần tử trong tập, nhưng thứ tự của các phần tử trong tập là ngẫu nhiên.
There are 3 values in the set There are 4 values in the set There are 6 values in the set pink orange brown blue yellow red ********************* Sorted: blue brown orange pink red yellow
QMap
QMap
lưu dữ liệu theo kiểu các cặp khóa-giá trị (key-value). Chúng ta có thể truy xuất phần tử thông qua key.
#include <QTextStream> #include <QMap> int main(void) { QTextStream out(stdout); QMap<QString, int> items = { {"coins", 5}, {"books", 3} }; items.insert("bottles", 7); QList<int> values = items.values(); out << "Values:" << endl; for (int val : values) { out << val << endl; } QList<QString> keys = items.keys(); out << "Keys:" << endl; for (QString key : keys) { out << key << endl; } QMapIterator<QString, int> it(items); out << "Pairs:" << endl; while (it.hasNext()) { it.next(); out << it.key() << ": " << it.value() << endl; } }
Trong ví dụ trên, chúng ta có các cặp key, mỗi key có một value.
QMap<QString, int> items = { {"coins", 5}, {"books", 3} };
Ta tạo ra một QMap
chứa hai cặp key-value.
items.insert("bottles", 7);
Ta thêm một cặp key-value bằng phương thức insert()
.
QList<int> values = items.values(); out << "Values:" << endl; for (int val : values) { out << val << endl; }
Chúng ta in toàn bộ các cặp ra màn hình. Ngoài ra ta có thể dùng phương thức values()
để lấy về một QList
chứa các value.
QList<QString> keys = items.keys(); out << "Keys:" << endl; for (QString key : keys) { out << key << endl; }
Ta in các key ra màn hình. Cũng giống như trên, ta có thể dùng phương thức keys()
để lấy về một QList
các key.
QMapIterator<QString, int> it(items);
QMapIterator
là biến lặp iterator cho QMap,
dùng để thao tác với QMap
.
while (it.hasNext()) { it.next(); out << it.key() << ": " << it.value() << endl; }
Ta dùng iterator này để duyệt qua QMap.
Phương thức key()
sẽ trả về khóa và phương thức value()
sẽ trả về giá trị.
Values: 3 7 5 Keys: books bottles coins Pairs: books: 3 bottles: 7 coins: 5
Sắp xếp các lớp do người dùng định nghĩa
Trong ví dụ dưới đây, chúng ta sẽ sắp xếp một QList
chứa các đối tượng thuộc lớp Book
do chúng ta tự định nghĩa.
class Book { public: Book(QString, QString); QString getAuthor() const; QString getTitle() const; private: QString author; QString title; };
Đây là file
header của lớp Book
.
#include <QString> #include "book.h" Book::Book(QString auth, QString tit) { author = auth; title = tit; } QString Book::getAuthor() const { return author; } QString Book::getTitle() const { return title; }
Đây là file cài dặt các phương thức của lớp Book
, trong lớp này ta cài đặt hai phương thức truy xuất dữ liệu.
#include <QTextStream> #include <QList> #include <algorithm> #include "book.h" bool compareByTitle(const Book &b1, const Book &b2) { return b1.getTitle() < b2.getTitle(); } int main(void) { QTextStream out(stdout); QList<Book> books = { Book("Jack London", "The Call of the Wild"), Book("Honoré de Balzac", "Father Goriot"), Book("Leo Tolstoy", "War and Peace"), Book("Gustave Flaubert", "Sentimental education"), Book("Guy de Maupassant", "Une vie"), Book("William Shakespeare", "Hamlet") }; std::sort(books.begin(), books.end(), compareByTitle); for (Book book : books) { out << book.getAuthor() << ": " << book.getTitle() << endl; } }
Ta tạo ra vài đối tượng Book,
đưa chúng vô QList
và sắp xếp với hàm
std::sort
.
bool compareByTitle(const Book &b1, const Book &b2) { return b1.getTitle() < b2.getTitle(); }
Phương thức compareByTitle()
là phương thức so sánh sẽ được sử dụng bởi hàm sort
.
std::sort(oks.begin(), books.end(), compareByTitle);
Hàm std::sort
sẽ sắp xếp các book dựa theo tựa book.
Honoré de Balzac: Father Goriot William Shakespeare: Hamlet Gustave Flaubert: Sentimental education Jack London: The Call of the Wild Guy de Maupassant: Une vie Leo Tolstoy: War and Peace
Trong bài này, chúng ta đã học về một số lớp lưu trữ dữ liệu thường dùng trong Qt 5.