List
Bạn sẽ học được
- List là dãy có thứ tự và thay đổi được.
- Truy cập, cắt, gán lại và thay slice.
- Thêm, xoá, sắp xếp — và khác biệt
sort()vớisorted(). - Bí danh (aliasing), sao chép nông và cái bẫy list lồng nhau.
- Khi nào list chưa phải cấu trúc dữ liệu phù hợp.
Khái niệm cốt lõi
List là dãy có thứ tự, thay đổi được, chứa được nhiều kiểu giá trị. Đây là cấu trúc dữ liệu dùng nhiều nhất trong Python:
nums = [3, 1, 2]
nums.append(4)
print(nums)
print(nums[0], nums[-1], nums[1:3])[3, 1, 2, 4]
3 4 [1, 2]append(4)thêm vào cuối, sửa list tại chỗ.nums[0]là phần tử đầu;nums[-1]là phần tử cuối (chỉ số âm đếm từ cuối).nums[1:3]lấy từ chỉ số 1 đến trước 3, tức hai phần tử[1, 2].- Slice luôn trả list mới; list gốc không đổi.
List giữ nguyên thứ tự chèn. Truy cập theo chỉ số là O(1), tìm theo giá trị là O(n).
Thêm và xoá
nums = [1, 2]
nums.extend([3, 4])
nums.insert(0, 0)
print(nums)[0, 1, 2, 3, 4]| Thao tác | Việc nó làm | Chi phí |
|---|---|---|
append(x) | Thêm một phần tử vào cuối | O(1) |
extend(iterable) | Thêm nhiều phần tử | O(k) |
insert(i, x) | Chèn tại vị trí i | O(n) |
remove(x) | Xoá lần xuất hiện đầu của x | O(n) |
pop() | Lấy và xoá phần tử cuối | O(1) |
pop(i) | Lấy và xoá tại i | O(n) |
del nums[i] | Xoá theo chỉ số | O(n) |
clear() | Xoá toàn bộ | O(n) |
insert(0, x) và pop(0) đẩy toàn bộ phần tử phía sau, nên chèn/xoá ở đầu list lớn rất chậm. Nếu bài toán chỉ thêm/xoá ở hai đầu, collections.deque phù hợp hơn.
nums = ["a", "b", "c", "b"]
nums.remove("b")
print(nums)
last = nums.pop()
print(last, nums)['a', 'c', 'b']
b ['a', 'c']remove("b") chỉ xoá lần đầu. Muốn xoá mọi lần, dùng comprehension. remove ném ValueError nếu không thấy; pop ném IndexError nếu list rỗng.
Truy cập và thay giá trị
nums = [10, 20, 30]
nums[1] = 99
print(nums)
nums[1:3] = [7, 8, 9]
print(nums)[10, 99, 30]
[10, 7, 8, 9]Gán slice có thể đổi độ dài list: ba phần tử bị thay bằng ba phần tử mới, hoặc nhiều/ít hơn. Gán chỉ số đơn chỉ thay một vị trí.
Các phép kiểm tra và tiện ích:
nums = [3, 1, 2]
print(nums.index(1), nums.count(2), len(nums), 9 in nums, 1 in nums)1 1 3 False Trueindex ném ValueError nếu không thấy; in an toàn hơn khi chỉ cần biết có hay không. in trên list là O(n) — với list lớn, kiểm tra nhiều lần nên dùng set.
Đảo và bước nhảy bằng slice:
a = [1, 2, 3]
print(a[::-1], a[::2])[3, 2, 1] [1, 3]sort() và sorted()
Đây là cặp dễ nhầm nhất:
scores = [85, 92, 78]
print(sorted(scores))
print(scores)
scores.sort(reverse=True)
print(scores)[78, 85, 92]
[85, 92, 78]
[92, 85, 78]sorted(scores)trả list mới, list gốc không đổi.scores.sort()sửa tại chỗ và trảNone.
Vì sort() trả None, dòng sau là lỗi kinh điển:
scores = [85, 92, 78]
result = scores.sort()
print(result, scores)None [78, 85, 92]Biến result là None, còn scores đã bị sắp xếp. Đừng gán kết quả của sort(). Với dữ liệu cần giữ nguyên bản gốc — rất thường gặp khi so sánh trước/sau — dùng sorted().
Cả hai nhận key để sắp theo tiêu chí phụ:
rows = [("An", 85), ("Bình", 92), ("Chi", 78)]
print(sorted(rows, key=lambda r: r[1], reverse=True))[('Bình', 92), ('An', 85), ('Chi', 78)]Bí danh và sao chép
Gán list không tạo bản sao — hai tên trỏ cùng một đối tượng:
a = [1, 2, 3]
b = a
b.append(4)
print(a)[1, 2, 3, 4]Sửa b cũng là sửa a. Muốn bản độc lập, phải sao chép rõ ràng:
a = [1, 2, 3]
b = a
b.append(4)
c = a.copy()
c.append(5)
print(a, c)[1, 2, 3, 4] [1, 2, 3, 4, 5]Ba cách sao chép nông tương đương: a.copy(), a[:], list(a).
Nhưng sao chép nông chỉ sao lớp ngoài; list lồng bên trong vẫn dùng chung:
a = [[1], [2]]
b = a.copy()
b[0].append(9)
print(a, b)[[1, 9], [2]] [[1, 9], [2]]b là list mới, nhưng b[0] và a[0] vẫn trỏ cùng list con. Muốn độc lập hoàn toàn, dùng copy.deepcopy(a). Với dữ liệu dạng bảng, lỗi này khiến "bản sao" vẫn bị thay đổi theo bản gốc.
+= khác +
a = [1, 2]
b = a
a += [3]
print(a, b)
c = a + [4]
print(a, c)[1, 2, 3] [1, 2, 3]
[1, 2, 3] [1, 2, 3, 4]+= gọi extend và sửa tại chỗ, nên b thấy thay đổi. + tạo list mới, nên c độc lập. Với tuple hay chuỗi (bất biến), += cũng tạo đối tượng mới — hành vi khác hẳn list. Đây là lý do không nên dùng += khi có nhiều tham chiếu tới cùng list.
Thực hành
- Tạo list doanh số,
appendthêm, in phần tử đầu/cuối và slice giữa. - Dùng
insert(0, ...),remove,popvà quan sát kết quả. - So sánh
sorted()vớisort(), thử gánresult = nums.sort(). - Tạo
b = a, sửab, kiểm traa; sau đó làm lại vớia.copy(). - Tái hiện cái bẫy list lồng nhau, rồi sửa bằng
deepcopy. - Sắp xếp danh sách
(tên, điểm)theo điểm giảm dần bằngkey.
Lỗi thường gặp
| Triệu chứng | Nguyên nhân | Cách sửa |
|---|---|---|
IndexError | Chỉ số ngoài phạm vi | Kiểm tra len hoặc dùng slice |
ValueError: x is not in list | remove/index không thấy | Kiểm tra in trước |
Biến thành None sau khi sort | x = x.sort() | Dùng sorted(x) hoặc bỏ gán |
| Sửa bản sao, bản gốc cũng đổi | Gán b = a | Dùng a.copy() |
| Bản sao vẫn đổi theo bản gốc | Sao chép nông list lồng | copy.deepcopy |
| Chèn đầu list rất chậm | insert(0, ...) O(n) | Dùng deque hoặc đảo chiều |
IndexError sau pop() | Không còn phần tử | Kiểm tra list rỗng trước |
Tóm tắt
- List có thứ tự, thay đổi được; slice trả bản mới.
append/popcuối là O(1); chèn/xoá giữa hoặc đầu là O(n).sorted()trả list mới;sort()sửa tại chỗ và trảNone.- Gán list là bí danh, không phải sao chép;
copy()chỉ nông. +=sửa tại chỗ,+tạo list mới.
Use ← → to move between lessons