
sort và sorted trong Python: sắp xếp list, dict
AIDev TeamTham vấn chuyên môn: Nguyễn Việt Chung
Đăng 10 phút đọc
Mục lục · 21
sort và sorted trong Python đều sắp xếp tăng dần, khác nhau ở chỗ list.sort() sửa thẳng list và trả về None, còn sorted() tạo list mới từ bất kỳ dãy nào. Bài này đi qua key, reverse, sắp xếp dict, xếp tên tiếng Việt cho đúng, kèm lỗi thật và số đo trên Python 3.15.1.
Muốn sắp xếp trong Python, bạn có hai cách: phương thức list.sort() sửa thẳng list đang có, còn hàm sorted() để nguyên dữ liệu gốc và trả về một list mới đã xếp. Hai cách nhận cùng tham số key và reverse, cùng thuật toán, cùng tốc độ. Chọn cách nào phụ thuộc vào việc bạn còn cần thứ tự cũ hay không.
Ngày 26/10/2026, mình chạy mọi ví dụ trong bài trên Python 3.15.1, máy CPU thuê theo giờ của AIDev Cloud chạy Ubuntu 24.04. Mấy điều nên nắm trước:
ds.sort()chỉ dùng được với list và trả vềNone. Viếtds = ds.sort()là mất luôn list.sorted()nhận mọi thứ lặp được (list, tuple, chuỗi, dict, set) và luôn trả về list.key=nhận một hàm, Python gọi hàm đó cho từng phần tử rồi xếp theo kết quả.Mặc định Python xếp chuỗi theo mã Unicode, nên tên tiếng Việt có dấu bị xếp sai. Bài có cách sửa ở mục riêng.
sort và sorted trong Python khác nhau thế nào?
Ví dụ dưới xếp một list điểm bằng cả hai cách:
diem = [7.5, 9, 6, 8.25]
moi = sorted(diem)
print("sorted():", moi, "| list gốc:", diem)
kq = diem.sort()
print("sort(): ", diem, "| giá trị trả về:", kq)

Sau dòng sorted(diem), list diem vẫn giữ thứ tự cũ. Sau dòng diem.sort(), chính list diem đã đổi, còn giá trị trả về là None. Python cố ý thiết kế như vậy để bạn không nhầm rằng sort() tạo ra list mới.
|
| |
|---|---|---|
Dùng với | chỉ list | mọi thứ lặp được: list, tuple, chuỗi, dict, set |
Dữ liệu gốc | bị sửa | giữ nguyên |
Trả về |
| list mới |
Bộ nhớ | không tạo list mới | tạo thêm một list cùng độ dài |
Nên dùng khi | không cần thứ tự cũ nữa | cần giữ dữ liệu gốc, hoặc dữ liệu không phải list |
Sắp xếp theo key và reverse ra sao?
reverse=True xếp giảm dần. key= nhận một hàm: Python gọi hàm đó với từng phần tử và xếp theo giá trị hàm trả về, còn phần tử thì giữ nguyên. Truyền key=len là xếp theo độ dài:
mon = ["phở", "bún chả", "cơm tấm", "bánh xèo", "chè"]
print(sorted(mon, key=len))
print(sorted(mon, key=len, reverse=True))
Khi cần một phép tính riêng, bạn viết hàm lambda (hàm không tên viết trong một dòng). Ví dụ lambda x: x[1] nghĩa là "lấy phần tử thứ hai của x".
Sắp xếp dict theo giá trị
Dict không có phương thức sort(). sorted(gia) chỉ trả về các khóa đã xếp. Muốn xếp theo giá trị, bạn xếp các cặp (khóa, giá trị) lấy từ gia.items(), rồi bọc lại bằng dict() nếu cần dict:
gia = {"phở": 55000, "bún chả": 45000, "cơm tấm": 40000, "bánh xèo": 60000}
print(sorted(gia)) # chỉ sắp xếp khóa
print(sorted(gia.items(), key=lambda x: x[1])) # theo giá, rẻ trước
print(dict(sorted(gia.items(), key=lambda x: x[1], reverse=True)))

Ở dòng đầu của kết quả, "phở" và "chè" cùng dài 3 ký tự, "bún chả" và "cơm tấm" cùng dài 7, và mỗi cặp giữ đúng thứ tự như trong list gốc. Tính chất này gọi là tính ổn định, mục sắp xếp theo nhiều tiêu chí nói kỹ hơn. Từ Python 3.7, dict giữ thứ tự thêm vào, nên dict tạo từ list đã xếp sẽ giữ thứ tự đó.
Sắp xếp theo nhiều tiêu chí như thế nào?
Cho key trả về một tuple (nhiều giá trị đặt trong ngoặc tròn, như ("B", -8.5)). Python so phần tử đầu của tuple trước, bằng nhau mới so tới phần tử sau. Muốn một tiêu chí tăng, tiêu chí kia giảm, với số thì đặt dấu trừ trước tiêu chí giảm:
hoc_vien = [
{"ten": "Lan", "lop": "B", "diem": 8.5},
{"ten": "Minh", "lop": "A", "diem": 7.0},
{"ten": "An", "lop": "B", "diem": 9.0},
{"ten": "Hòa", "lop": "A", "diem": 8.5},
]
for hv in sorted(hoc_vien, key=lambda h: (h["lop"], -h["diem"])):
print(hv["lop"], hv["ten"], hv["diem"])
Dòng key này xếp theo lớp tăng dần, trong cùng lớp thì điểm cao trước. Kết quả ở nửa trên của ảnh dưới.
Nửa dưới của ảnh là ví dụ về tính ổn định. Tài liệu Python ghi rõ mọi phép sắp xếp đều ổn định: các phần tử có cùng khóa giữ nguyên thứ tự ban đầu. Mình xếp năm đơn hàng theo tỉnh, hai đơn Hà Nội vẫn đứng theo thứ tự DH01 rồi DH03 như lúc chưa xếp:

Trong ảnh còn thấy một lỗi: Đà Nẵng đứng sau Hà Nội. Theo bảng chữ cái tiếng Việt, Đ phải đứng trước H.
Sắp xếp tên tiếng Việt có dấu thế nào cho đúng?
Python so chuỗi theo mã Unicode của từng ký tự. Chữ không dấu A đến Z có mã nhỏ, còn Á, Â, Đ, Ơ có mã lớn hơn, nên mọi tên bắt đầu bằng chữ có dấu bị đẩy xuống cuối. Mình thử với 12 tên, lần đầu chạy trên máy mới còn gặp thêm lỗi locale (bộ quy tắc ngôn ngữ của hệ điều hành) chưa được cài:

locale.Error: unsupported locale setting
Cách 1: dùng locale vi_VN của hệ điều hành
Trên Ubuntu, bạn sinh locale tiếng Việt bằng lệnh locale-gen vi_VN.UTF-8 (chạy bằng quyền root). Sau đó locale.strxfrm đổi mỗi chuỗi thành một khóa so sánh theo quy tắc tiếng Việt, và bạn truyền nó vào key:
import locale
ten = ["Bình", "An", "Đức", "Ánh", "Dũng", "Châu", "Ân", "Anh", "Ơn", "Oanh", "Ảnh", "Ạnh"]
locale.setlocale(locale.LC_COLLATE, "vi_VN.UTF-8")
print(sorted(ten, key=locale.strxfrm))

Cách này phụ thuộc vào máy. Tên locale trên Windows khác Linux, và máy chủ thuê thường chưa cài sẵn locale tiếng Việt, đúng như lỗi mình gặp ở trên. Theo tài liệu module locale, setlocale còn đổi thiết lập cho cả chương trình, không riêng phép sắp xếp.
Cách 2: tự viết hàm khóa theo bảng chữ cái
Hàm khoa_viet dưới đây chỉ dùng standard library (các module có sẵn khi cài Python). Hàm tách mỗi ký tự thành chữ cái gốc (a, ă, â, đ…) và dấu thanh. Khi xếp, chữ cái được so trước. Hai chuỗi có chữ cái giống hệt nhau mới xét tới dấu thanh, theo thứ tự ngang, huyền, hỏi, ngã, sắc, nặng:
import unicodedata
CHU = "aăâbcdđeêghiklmnoôơpqrstuưvxy"
THANH = {"": 0, "\u0300": 1, "\u0309": 2, "\u0303": 3, "\u0301": 4, "\u0323": 5} # ngang, huyền, hỏi, ngã, sắc, nặng
def khoa_viet(chuoi):
goc, thanh = [], []
for kt in chuoi.lower():
tach = unicodedata.normalize("NFD", kt)
dau = "".join(c for c in tach if c in THANH and c)
chu = unicodedata.normalize("NFC", "".join(c for c in tach if c not in THANH))
goc.append(CHU.index(chu) if chu in CHU else 100 + ord(chu))
thanh.append(THANH[dau])
return goc, thanh
lop = ["Nguyễn Văn Bình", "Trần Thị An", "Lê Minh Đức", "Phạm Thu Anh", "Đỗ Hoàng An"]
print(sorted(lop, key=lambda t: (khoa_viet(t.split()[-1]), khoa_viet(t))))
Dòng cuối xếp danh sách lớp kiểu Việt Nam: theo tên (từ cuối cùng) trước, trùng tên thì xét cả họ tên.

Với 12 tên trên, hai cách cho cùng một thứ tự. Mình thử thêm 2.000 nhóm, mỗi nhóm năm chuỗi ghép ngẫu nhiên từ các chữ có dấu (không phải tên thật), thì 1.426 nhóm cho thứ tự khác nhau. Ví dụ locale vi_VN xếp "ắeu" trước "aod", còn khoa_viet xếp "aod" trước vì a đứng trước ă trong bảng chữ cái. Với tên người thật, mình chưa gặp trường hợp lệch, nhưng nếu thứ tự phải đúng tuyệt đối (danh sách thi, danh sách in), nên kiểm lại bằng mắt vài chục dòng đầu.
sort và sorted chạy nhanh hay chậm?
Mình xếp 1 triệu số nguyên ngẫu nhiên, mỗi phép đo chạy năm lần bằng timeit (module đo thời gian có sẵn), lấy lần nhanh nhất:

Phép đo (1 triệu phần tử) | Thời gian (ms) |
|---|---|
| 348,8 |
| 357,3 |
chỉ chép list bằng | 10,0 |
| 86,5 |
| 573,8 |
| 593,1 |
sort() và sorted() nhanh như nhau. Bản sort() phải chép list trước để mỗi lần đo đều xếp dữ liệu ngẫu nhiên, nhưng phép chép chỉ tốn 10 ms. List đã xếp sẵn hoặc xếp ngược sẵn được xếp nhanh gấp khoảng bốn lần, vì thuật toán của Python nhận ra các đoạn đã có thứ tự. Thêm key=lambda làm chậm 65%, vì Python phải gọi hàm lambda một triệu lần. Mình đo lại lần hai, các số lệch tới 13% nhưng thứ tự nhanh chậm giữ nguyên, riêng key=lambda lần này chậm hơn 42%.
Về bộ nhớ, sorted() trên list 1 triệu số làm RAM đỉnh của chương trình tăng từ 50,4 MB lên 61,8 MB, tức thêm 11,4 MB cho list mới. List vài trăm nghìn phần tử trở xuống thì khoản này không đáng lo.
Những lỗi nào hay gặp khi sắp xếp?
Gán lại kết quả của sort(), xếp list trộn chữ và số
TypeError: 'NoneType' object is not subscriptable
TypeError: '<' not supported between instances of 'str' and 'int'

Lỗi đầu đến từ dòng ds = ds.sort(): sort() trả về None, nên ds thành None và không lấy phần tử được nữa. Sửa bằng cách chỉ viết ds.sort(), hoặc ds = sorted(ds). Lỗi thứ hai xảy ra vì Python 3 không so được chuỗi với số. Dữ liệu đọc từ file hoặc từ input() thường bị trộn như vậy. Bạn đổi hết về số trước khi xếp.
Gọi sort() trên tuple hoặc dict
AttributeError: 'tuple' object has no attribute 'sort'
AttributeError: 'dict' object has no attribute 'sort'

Tuple không sửa được nên không có sort(). Dict cũng không có. Cả hai trường hợp đều dùng sorted(), kết quả là một list.
Chuỗi số xếp sai thứ tự
Lỗi này không có thông báo nào. List ["10", "9", "100", "2"] xếp ra ['10', '100', '2', '9'], vì chuỗi được so từng ký tự từ trái sang và "1" nhỏ hơn "2". Thêm key=int thì ra đúng ['2', '9', '10', '100']:

Khi nào không nên dùng sort hay sorted?
Khi chỉ cần phần tử lớn nhất hoặc nhỏ nhất, bạn không cần tới sort và sorted trong Python: max() và min() đi qua dữ liệu một lần, nhanh hơn xếp cả list rồi lấy phần tử đầu. Khi cần vài phần tử lớn nhất trong một list rất dài, module heapq có nlargest().
Với bảng dữ liệu nhiều cột, như file Excel hay CSV hàng nghìn dòng, library pandas có sort_values() xếp theo một hoặc nhiều cột mà không phải viết lambda. Bài làm sạch dữ liệu với pandas dùng pandas trên file đơn hàng của một cửa hàng mô phỏng, nếu bạn đang làm việc với bảng thì nên đọc tiếp bài đó.
Câu hỏi thường gặp
sort() có trả về list đã sắp xếp không?
Không. list.sort() sắp xếp ngay trên list và trả về None. Muốn có kết quả để gán cho biến khác, dùng sorted().
Làm sao sắp xếp giảm dần?
Thêm reverse=True, ví dụ sorted(ds, reverse=True) hoặc ds.sort(reverse=True). Trong phép đo tốc độ của bài, reverse=True chậm hơn xếp tăng dần một chút: 14% ở lần đo đầu (397,1 so với 348,8 ms), 4% ở lần đo thứ hai.
Python dùng thuật toán sắp xếp gì?
CPython dùng một biến thể của merge sort, kết hợp với insertion sort cho các đoạn ngắn. Chi tiết nằm trong file Objects/listsort.txt của mã nguồn CPython. Người mới chỉ cần nhớ hai điều đã thấy trong phép đo: dữ liệu gần như đã xếp sẵn được xếp rất nhanh, và thứ tự của các phần tử có khóa bằng nhau luôn được giữ.
sorted() dùng được với chuỗi không?
Được, nhưng kết quả là list các ký tự, ví dụ sorted("bca") ra ['a', 'b', 'c']. Muốn ghép lại thành chuỗi, dùng "".join(sorted("bca")).
Bước tiếp theo
sort, sorted và key nằm ở chương 3 của ebook Python từ số 0, trong phần list, tuple và dict, kèm bài toán phân tích điểm thi của 200 thí sinh. Nếu bạn chưa chắc về vòng lặp mà các ví dụ ở đây dùng, xem lại bài vòng lặp for trong Python. Chương trình đếm từ và ghi chi tiêu trong bài 15 chương trình Python mẫu cũng dùng sorted() với key, bạn có thể mở ra sửa thử.
Thứ tự học đầy đủ từ biến tới OOP nằm trong bài học Python từ số 0.
Code trong bài chạy trên Python 3.15.1, máy CPU Starter của AIDev Cloud (Intel Xeon E5-2680 v4, 8 vCPU, 16 GB RAM, Ubuntu 24.04.4, glibc locale vi_VN.UTF-8), ngày 26/10/2026.
Chuyên mục
Học PythonTham vấn chuyên môn
Nhà sáng lập AIDev và VietPlatform · Thạc sĩ AI MSE
- Tốt nghiệp thủ khoa xuất sắc Thạc sĩ AI MSE.
- Đồng sáng lập, CTO E-University, SVOnline: số hóa 10+ đại học, 40.000+ sinh viên.
- Xây hệ thống AI cho doanh nghiệp tại VietPlatform.


