Python sorted() + key: 5 Cách Sắp Xếp Dữ Liệu Thực Tế Trong Lập Trình
- Home
- Python sorted() + key: 5 Cách Sắp Xếp Dữ Liệu Thực Tế Trong Lập Trình
Trong quá trình phát triển ứng dụng web, xử lý dữ liệu hệ thống hay phân tích dữ liệu, việc sắp xếp (sorting) là thao tác diễn ra liên tục. Python cung cấp hàm built-in sorted() cực kỳ mạnh mẽ, nhưng sức mạnh thực sự của nó chỉ bộc lộ khi bạn làm chủ tham số key.
Bài viết này từ DCSoftTech sẽ hướng dẫn chi tiết cú pháp, nguyên lý hoạt động và 5 trường hợp ứng dụng thực tế phổ biến nhất của sorted() kết hợp với key.
sorted() Trong PythonHàm sorted() nhận vào một cấu trúc dữ liệu có thể lặp (Iterable) như List, Tuple, Dictionary… và trả về một danh sách mới đã được sắp xếp. Điều này giúp giữ nguyên dữ liệu gốc (tránh side-effect).
sorted(iterable, key=None, reverse=False)
iterable: Chuỗi, danh sách, tuple, dictionary, set… cần sắp xếp.
key: Một hàm (function) nhận vào từng phần tử của iterable và trả về một giá trị làm “tiêu chí” để so sánh.
reverse: False (mặc định – tăng dần) hoặc True (giảm dần).
sorted() và list.sort()list.sort() chỉ áp dụng cho đối tượng list, thay đổi trực tiếp danh sách ban đầu (in-place) và trả về None.
sorted() áp dụng cho mọi iterable, tạo ra list mới và không làm ảnh hưởng đến dữ liệu cũ.
key Hoạt Động Như Thế Nào?Khi bạn truyền tham số key=function_name, Python sẽ:
Áp dụng function_name cho từng phần tử trong danh sách.
Lấy giá trị trả về từ hàm đó làm khóa so sánh (Sort Key).
Sắp xếp các phần tử dựa trên thứ tự của các khóa này.
Bạn có thể truyền vào một hàm có sẵn (như len, str.lower), một hàm tự định nghĩa bằng def, một lambda function, hoặc hàm từ thư viện operator.
sorted() + keyMặc định, Python sắp xếp chuỗi theo bảng mã ASCII (chữ hoa đứng trước chữ thường). Nhờ tham số key, bạn có thể tùy chỉnh lại theo logic mong muốn.
####Ví dụ 1: Sắp xếp danh sách tên theo độ dài
names = ["Nguyen Van A", "Le B", "Tran Thi Minh C", "Do D"]
# Sắp xếp từ ngắn nhất đến dài nhất
sorted_names = sorted(names, key=len)
print(sorted_names)
# Kết quả: ['Do D', 'Le B', 'Nguyen Van A', 'Tran Thi Minh C']
brands = ["apple", "Samsung", "Xiaomi", "ASUS"]
# Không phân biệt chữ hoa/thường
sorted_brands = sorted(brands, key=str.lower)
print(sorted_brands)
# Kết quả: ['apple', 'ASUS', 'Samsung', 'Xiaomi']
Khi nhận dữ liệu JSON từ API hoặc query từ cơ sở dữ liệu, dữ liệu thường nằm ở dạng List[Dict].
employees = [
{"name": "Dung", "age": 28, "salary": 1500},
{"name": "An", "age": 22, "salary": 1200},
{"name": "Binh", "age": 35, "salary": 2000},
]
# Sử dụng lambda function làm key
sorted_by_age = sorted(employees, key=lambda emp: emp["age"])
print(sorted_by_age)
# Kết quả:
# [
# {'name': 'An', 'age': 22, 'salary': 1200},
# {'name': 'Dung', 'age': 28, 'salary': 1500},
# {'name': 'Binh', 'age': 35, 'salary': 2000}
# ]
Tối ưu hiệu năng: Thay vì dùng
lambda, với các tập dữ liệu lớn, bạn nên dùngitemgettertừ moduleoperatorđể chạy nhanh hơn.
from operator import itemgetter
sorted_by_salary = sorted(employees, key=itemgetter("salary"), reverse=True)
Trong thực tế, bạn thường phải sắp xếp theo tiêu chí ưu tiên 1, nếu bằng nhau thì so sánh tiếp tiêu chí 2.
Ví dụ này trả về một Tuple (-student["score"], student["name"]) trong hàm key:
Giá trị âm -student["score"] đảo ngược thứ tự số, giúp điểm cao xếp trước.
Tên giữ nguyên dạng chuỗi để xếp theo thứ tự bảng chữ cái.
students = [
{"name": "Minh", "score": 8.5},
{"name": "An", "score": 9.0},
{"name": "Hoa", "score": 8.5},
{"name": "Binh", "score": 9.0},
]
# Ưu tiên score giảm dần (-), sau đó đến name tăng dần (+)
sorted_students = sorted(
students, key=lambda s: (-s["score"], s["name"])
)
for s in sorted_students:
print(f"{s['name']}: {s['score']}")
# Kết quả in ra:
# An: 9.0
# Binh: 9.0
# Hoa: 8.5
# Minh: 8.5
Khi lập trình OOP, dữ liệu của bạn là các thể hiện (instance) của một class. Bạn có thể dùng key hoặc attrgetter để sắp xếp.
from operator import attrgetter
class Product:
def __init__(self, name, price, stock):
self.name = name
self.price = price
self.stock = stock
def __repr__(self):
return f"Product({self.name}, Price: {self.price}, Stock: {self.stock})"
products = [
Product("Laptop", 1200, 10),
Product("Mouse", 25, 50),
Product("Keyboard", 75, 20),
]
# Sắp xếp danh sách sản phẩm theo giá tăng dần
sorted_products = sorted(products, key=attrgetter("price"))
print(sorted_products)
# Kết quả: [Product(Mouse, Price: 25, Stock: 50), Product(Keyboard, Price: 75, Stock: 20), Product(Laptop, Price: 1200, Stock: 10)]
Dictionary trong Python (từ bản 3.7+) giữ thứ tự thêm vào. Muốn sắp xếp một Dictionary theo giá trị (Value), bạn kết hợp sorted() với .items().
leaderboard = {"player_A": 450, "player_B": 1200, "player_C": 890, "player_D": 1200}
# sorted() trả về danh sách các tuple (key, value)
sorted_tuples = sorted(
leaderboard.items(), key=lambda item: item[1], reverse=True
)
# Chuyển đổi lại thành Dictionary
sorted_leaderboard = dict(sorted_tuples)
print(sorted_leaderboard)
# Kết quả: {'player_B': 1200, 'player_D': 1200, 'player_C': 890, 'player_A': 450}
key Của DCSoftTechƯu tiên operator.itemgetter / attrgetter cho dữ liệu lớn: Dùng hàm trong module operator sẽ tối ưu về mặt hiệu năng (C-speed) tốt hơn so với gọi lambda function trong các tập dữ liệu có hàng trăm ngàn bản ghi.
Kỹ thuật đổi dấu - cho dữ liệu số: Khi cần sắp xếp đa tiêu chí mà có tiêu chí tăng, tiêu chí giảm, hãy dùng dấu - cho các trường dữ liệu kiểu số (int, float).
Tính ổn định của thuật toán (Stable Sort): Python sử dụng thuật toán Timsort. Nó đảm bảo nếu hai phần tử có giá trị key bằng nhau, thứ tự xuất hiện ban đầu của chúng sẽ được giữ nguyên.
Tránh xử lý logic quá nặng trong key: Hàm key sẽ chạy $N$ lần (với $N$ là số lượng phần tử). Tránh việc query DB hoặc gọi API bên trong hàm key.
Làm chủ hàm sorted() và tham số key sẽ giúp bạn viết mã nguồn Python ngắn gọn, tinh tế và tối ưu hơn rất nhiều. Từ việc sắp xếp danh sách cơ bản đến xử lý các cấu trúc dữ liệu phức tạp trong các dự án thực tế, sorted() luôn là công cụ hàng đầu.
Hy vọng bài viết thủ thuật Python này từ DCSoftTech hữu ích cho công việc lập trình của bạn!