← Lập trình Python cơ bản

Bài 7 · Vận dụng · 24 phút· Cập nhật 11/06/2026

List · tuple · dict · set

Biên soạn bởi Nguyễn Anh Tuấn

Cấu trúc dữ liệu Python: list, tuple, dict, set - chọn đúng cấu trúc cho từng việc, và bản chất dict là hash table (bảng băm) nên tra cứu O(1).

list giữ nhiều giá trị có thứ tự, truy cập theo chỉ số (như bài str), và đổi được (thêm/xoá/sắp xếp):

list.py

xs = [3, 1, 2]
xs.append(4)      # them vao cuoi
xs.sort()         # sap xep tai cho
print(xs)
print(xs[0], xs[-1])   # phan tu dau & cuoi

Kết quả khi chạy

[1, 2, 3, 4]
1 4
  • Tạo: [a, b, c]; truy cập xs[i]; cắt xs[a:b] như str.
  • Đổi tại chỗ: append, insert, pop, remove, sort, reverse.
  • Mutable → cẩn thận “aliasing” (bài Biến & đối tượng).

tuple giống list nhưng immutable - hợp cho một nhóm giá trị cố định. Rất tiện để gán nhiều biến (unpacking) và trả nhiều giá trị từ hàm:

tuple.py

diem = (10.5, 20.3)    # mot toa do co dinh
x, y = diem            # unpacking
print(x, y)

def chia(a, b):
    return a // b, a % b   # tra ve mot tuple
thuong, du = chia(17, 5)
print(thuong, du)

Kết quả khi chạy

10.5 20.3
3 2
  • Tạo: (a, b) - immutable, không append/sort được.
  • Unpacking: x, y = cap; hoán đổi nhanh a, b = b, a.
  • tuple immutable nên dùng được làm KEY của dict; list thì không.

dict lưu các cặp key → value - tra theo key thay vì theo chỉ số. Từ Python 3.7, dict giữ thứ tự chèn:

dict.py

db = {"lan": "0901", "nam": "0902"}
print(db["lan"])          # tra theo key
print(db.get("an", "?"))  # an toan: "?" neu vang

db["hoa"] = "0903"        # them moi
for k, v in db.items():
    print(k, "->", v)

Kết quả khi chạy

0901
?
lan -> 0901
nam -> 0902
hoa -> 0903
  • Tạo: {"key": value}; tra db[key]; thêm/đổi db[key] = value.
  • .get(key, mặc_định) tránh KeyError khi key vắng.
  • Duyệt: for k, v in db.items(); chỉ key: db.keys(); chỉ value: db.values().

Vì sao tra cứu trong dict gần như tức thì dù có hàng triệu key? Vì dict là một hash table (bảng băm): nó “băm” key thành chỉ số một ô, rồi tới thẳng ô đó - không quét cả bảng. Bấm tra thử từng key:

dict danh bạ - tra cứu key:
hash("lan") = 315 % 5 = ô 0 → tới thẳng ô đó, không quét cả bảng
ô 0
lan: 0901 tuan: 0904
ô 1
nam: 0902 mai: 0905
ô 2
hoa: 0903
ô 3
(trống)
ô 4
(trống)
✓ Thấy "lan" → 0901 ở ô 0, chỉ phải so 1 mục trong ô. Không đụng các ô khác - đó là vì sao dict tra cứu gần như tức thì (O(1)), khác list phải quét lần lượt.

Trung thực

Công cụ trên dùng hàm băm đồ chơi (cộng mã ký tự) và “str” để dễ hiểu. CPython thật dùng hàm băm mạnh hơn nhiều (SipHash) và cách lưu khác (open addressing) - nhưng ý tưởng thì y hệt: băm key → tới đúng ô → tìm. Đó là lý do dict (và set) tra cứu O(1) trung bình.

set là tập các phần tử không trùng, không thứ tự, kiểm “có trong tập” rất nhanh (cũng là hash table). Hợp để loại trùng và làm phép tập hợp:

set.py

s = {1, 2, 2, 3}      # trung tu dong bi loai
print(s, 2 in s)

a = {1, 2, 3}
b = {2, 3, 4}
print(a & b)          # giao
print(a | b)          # hop

Kết quả khi chạy

{1, 2, 3} True
{2, 3}
{1, 2, 3, 4}
  • Loại trùng nhanh: set(danh_sach) → các giá trị duy nhất.
  • Phép tập hợp: & giao, | hợp, - hiệu; x in s kiểm tra rất nhanh.
  • Không thứ tự, không truy cập theo chỉ số (khác list).

Chọn đúng cấu trúc

Dãy đổi được, có thứ tự → list. Nhóm cố định / trả nhiều giá trị → tuple. Tra theo tên/khoá → dict. Tập duy nhất / kiểm thành viên / loại trùng → set.

Câu hỏi thường gặp

list khi cần một dãy CÓ THỂ ĐỔI (thêm/xoá/sắp xếp) - vd danh sách việc. tuple khi một nhóm giá trị CỐ ĐỊNH, không đổi - vd toạ độ (x, y), một bản ghi. tuple còn dùng được làm key của dict (vì immutable), list thì không.

list phải QUÉT lần lượt tới khi gặp (trung bình O(n)). dict là HASH TABLE: nó “băm” key thành chỉ số một ô, rồi tới thẳng ô đó và chỉ dò vài mục - gần như tức thì (O(1) trung bình), không phụ thuộc dict lớn cỡ nào.

Key phải “băm được” (hashable) - với các kiểu có sẵn, đó là các kiểu IMMUTABLE: int/float, str, tuple (chứa toàn immutable). list/dict/set KHÔNG làm key được vì chúng đổi được (đổi thì hash đổi, hỏng cấu trúc). Value thì kiểu gì cũng được.

Có - từ Python 3.7, dict giữ ĐÚNG thứ tự bạn chèn key. (Trước đó không đảm bảo.) set thì KHÔNG có thứ tự xác định.

set không có thứ tự, không trùng lặp, và kiểm “có trong tập không” rất nhanh (cũng là hash table). Dùng set để LOẠI TRÙNG (set(danh_sach)) hoặc làm phép giao/hợp/hiệu. Đổi lại set không truy cập theo chỉ số như list.

Truy cập key không tồn tại bằng db[key] sẽ KeyError. Dùng db.get(key) (trả None nếu vắng) hoặc db.get(key, mac_dinh) để có giá trị mặc định an toàn.

Tick những điều em tự tin làm được. Càng lên cao, em càng hiểu sâu.

Tick những điều em tự tin làm được sau khi học bài này. 0/6

Trả lời vài câu để chắc rằng em đã nắm bài.

Câu 1/3 Điểm: 0

Vì sao tra cứu trong dict gần như tức thì (O(1) trung bình) dù dict rất lớn?

  1. 1

    Thao tác list

    Tạo list [5, 2, 8, 1], thêm 3 vào cuối, sắp xếp tăng dần, in ra.

    Hoàn thành khi: append(3) rồi sort()[1, 2, 3, 5, 8].

  2. 2

    Unpacking

    Cho diem = (10.5, 20.3), gán x, y từ tuple và in “x=… y=…”.

    Hoàn thành khi: x, y = diem → x=10.5 y=20.3.

  3. 3

    Đếm bằng dict

    Đếm số lần xuất hiện mỗi ký tự trong "banana" bằng một dict.

    Hoàn thành khi: Duyệt str, dem[c] = dem.get(c, 0) + 1{b:1, a:3, n:2}.

  4. 4

    Tra cứu hash

    Dùng công cụ Bước 4: tra "tuan" và "an". Vì sao "tuan" phải dò 2 mục còn "an" không thấy?

    Hoàn thành khi: "tuan" trùng ô với "lan" (va chạm) nên dò 2; "an" băm về ô của "hoa" nhưng không khớp → không có.

  5. 5

    Loại trùng

    Cho [1, 2, 2, 3, 3, 3], lấy danh sách các giá trị KHÁC NHAU bằng set.

    Hoàn thành khi: list(set([...])) → các phần tử duy nhất {1, 2, 3}.

  6. 6

    Phép tập hợp

    Hai lớp A={"Lan","Nam","Hoa"}B={"Nam","Mai"}. Ai học CẢ hai lớp?

    Hoàn thành khi: A & B (giao) → {"Nam"}.