Python中sorted()排序函數(shù)與自定義排序規(guī)則
一、開篇:排序——數(shù)據(jù)處理的基本功
排序是編程中最常見的操作之一。Python提供了兩個排序工具:list.sort()(原地排序)和sorted()(返回新排序結(jié)果)。其中sorted()更靈活、更通用——它能排序任何可迭代對象,還能自定義排序規(guī)則。
?? 先看最基礎(chǔ)的用法:
# sorted()的基本用法 numbers = [3, 1, 4, 1, 5, 9, 2, 6] sorted_numbers = sorted(numbers) print(sorted_numbers) # [1, 1, 2, 3, 4, 5, 6, 9] print(numbers) # [3, 1, 4, 1, 5, 9, 2, 6] ← 原列表不變! # list.sort()——原地排序,直接修改原列表 numbers.sort() print(numbers) # [1, 1, 2, 3, 4, 5, 6, 9] ← 被修改了 # ?? 關(guān)鍵區(qū)別: # sorted(iterable) → 返回新列表,原數(shù)據(jù)不變,可用于任何可迭代對象 # list.sort() → 原地排序,不返回新列表,只能用于列表
?? sorted()的核心優(yōu)勢在于它的key參數(shù)——讓你能按任意規(guī)則排序,這個參數(shù)是Python排序系統(tǒng)的靈魂。
二、sorted()的基本參數(shù)
2.1 三個參數(shù)詳解
# sorted(iterable, key=None, reverse=False) # iterable: 要排序的可迭代對象 # key: 排序依據(jù)的函數(shù)(接收每個元素,返回用于比較的值) # reverse: 是否降序(True=降序,F(xiàn)alse=升序) # reverse參數(shù)——升降序控制 numbers = [3, 1, 4, 1, 5] print(sorted(numbers)) # [1, 1, 3, 4, 5] 升序 print(sorted(numbers, reverse=True)) # [5, 4, 3, 1, 1] 降序 # key參數(shù)——自定義排序依據(jù) words = ["banana", "apple", "Cherry", "date", "Elderberry"] # 默認排序——按Unicode碼點(大寫字母在小寫字母前) print(sorted(words)) # ['Cherry', 'Elderberry', 'apple', 'banana', 'date'] # 按字母順序(忽略大小寫) print(sorted(words, key=str.lower)) # ['apple', 'banana', 'Cherry', 'date', 'Elderberry'] # 按單詞長度排序 print(sorted(words, key=len)) # ['date', 'apple', 'banana', 'Cherry', 'Elderberry']
2.2 key參數(shù)的詳解
# ?? key函數(shù)的規(guī)則:
# 1. key接收一個參數(shù)(序列中的每個元素)
# 2. key返回一個用于比較的值
# 3. 排序根據(jù)key的返回值進行(不是原始元素)
# 4. 原始元素不變——只是排序的依據(jù)變了
# 絕對值排序
numbers = [-5, 3, -1, 4, -2]
print(sorted(numbers, key=abs)) # [-1, -2, 3, 4, -5]
# 按字符串中數(shù)字的大小排序
codes = ["item2", "item10", "item1", "item20"]
print(sorted(codes))
# ['item1', 'item10', 'item2', 'item20'] ← 字典序!item10在item2前!
import re
def extract_number(s):
"""提取字符串中的數(shù)字"""
match = re.search(r'\d+', s)
return int(match.group()) if match else 0
print(sorted(codes, key=extract_number))
# ['item1', 'item2', 'item10', 'item20'] ← 按數(shù)字大小排!
# 按時間排序
times = ["2024-03-15", "2023-12-01", "2024-01-20", "2023-06-10"]
print(sorted(times)) # 字符串比較恰好對日期格式有效!
# ['2023-06-10', '2023-12-01', '2024-01-20', '2024-03-15']
三、lambda作為key——最常用的排序方式
3.1 按字典字段排序
# ?? 排序字典列表——職場中最常用的技能
employees = [
{"name": "張三", "age": 28, "salary": 15000, "department": "技術(shù)部"},
{"name": "李四", "age": 35, "salary": 20000, "department": "管理部"},
{"name": "王五", "age": 22, "salary": 12000, "department": "技術(shù)部"},
{"name": "趙六", "age": 30, "salary": 18000, "department": "市場部"},
{"name": "錢七", "age": 25, "salary": 13000, "department": "技術(shù)部"},
]
# 按年齡排序
by_age = sorted(employees, key=lambda e: e["age"])
print("按年齡:", [e["name"] for e in by_age])
# ['王五', '錢七', '張三', '趙六', '李四']
# 按薪資降序
by_salary = sorted(employees, key=lambda e: e["salary"], reverse=True)
print("按薪資降序:", [(e["name"], e["salary"]) for e in by_salary])
# [('李四', 20000), ('趙六', 18000), ('張三', 15000), ('錢七', 13000), ('王五', 12000)]
# 按年齡排序,同年齡按薪資降序(多級排序)
by_age_salary = sorted(employees, key=lambda e: (e["age"], -e["salary"]))
print("年齡+薪資:", [(e["name"], e["age"], e["salary"]) for e in by_age_salary])
3.2 多級排序
# ?? 多級排序:key返回一個元組
# Python按元組的元素順序依次比較
# 先按部門,再按薪資降序
results = sorted(employees, key=lambda e: (e["department"], -e["salary"]))
for e in results:
print(f" {e['department']} - {e['name']}: ¥{e['salary']}")
# 管理部 - 李四: ¥20000
# 技術(shù)部 - 張三: ¥15000
# 技術(shù)部 - 錢七: ¥13000
# 技術(shù)部 - 王五: ¥12000
# 市場部 - 趙六: ¥18000
# ?? 技巧:降序字段用負號
# 數(shù)字降序:-e["salary"](注意:這只對數(shù)字有效)
# 字符串降序:沒法用負號,需要分兩次排序或用functools.cmp_to_key
# 多級排序的另一種方法:多次sorted()(利用穩(wěn)定性)
# Python的排序是穩(wěn)定的——相同key的元素保持原來的相對順序
# 先按次要key排,再按主要key排
result = sorted(employees, key=lambda e: e["salary"], reverse=True)
result = sorted(result, key=lambda e: e["department"])
# 結(jié)果:同一部門內(nèi),按薪資降序
四、高級排序技巧
4.1 使用operator模塊
from operator import itemgetter, attrgetter, methodcaller
# itemgetter——獲取字典的指定字段(相當于lambda e: e["key"])
# 比lambda稍快一些,而且更簡潔
by_department = sorted(employees, key=itemgetter("department"))
print([e["department"] for e in by_department])
# itemgetter多級排序
by_dept_salary = sorted(employees, key=itemgetter("department", "salary"))
# attrgetter——獲取對象的屬性
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
students = [
Student("Alice", 85),
Student("Bob", 92),
Student("Charlie", 78),
]
by_score = sorted(students, key=attrgetter("score"), reverse=True)
for s in by_score:
print(f"{s.name}: {s.score}")
4.2 自定義對象的排序
from functools import total_ordering
# 方法一:實現(xiàn)比較方法
class Task:
def __init__(self, name, priority, due_date):
self.name = name
self.priority = priority
self.due_date = due_date
def __lt__(self, other):
"""小于比較:先按priority,再按due_date"""
if self.priority != other.priority:
return self.priority < other.priority
return self.due_date < other.due_date
def __repr__(self):
return f"Task({self.name}, pri={self.priority}, due={self.due_date})"
tasks = [
Task("寫報告", 2, "2024-06-15"),
Task("修復Bug", 1, "2024-06-10"),
Task("開會", 2, "2024-06-12"),
Task("代碼審查", 1, "2024-06-08"),
]
print(sorted(tasks))
# [Task(代碼審查, pri=1, due=2024-06-08), Task(修復Bug, pri=1, due=2024-06-10),
# Task(開會, pri=2, due=2024-06-12), Task(寫報告, pri=2, due=2024-06-15)]
# 方法二:使用key(更靈活,不修改類)
tasks_sorted = sorted(tasks, key=lambda t: (t.priority, t.due_date))
五、實戰(zhàn)案例
5.1 日志按時間排序
# 場景:排序雜亂的日志條目
logs = [
"[2024-03-15 14:30:22] ERROR 數(shù)據(jù)庫連接失敗",
"[2024-03-15 14:25:10] INFO 服務(wù)器啟動",
"[2024-03-15 14:32:05] WARNING 內(nèi)存使用率85%",
"[2024-03-15 14:25:10] DEBUG 加載配置文件",
"[2024-03-15 14:28:45] INFO 用戶登錄成功",
]
def extract_timestamp(log_line):
"""從日志行中提取時間戳"""
return log_line[1:20] # 提取 "[2024-03-15 14:30:22]" 中的時間
sorted_logs = sorted(logs, key=extract_timestamp)
for log in sorted_logs:
print(log)
# 按時間正序排列
# 對于同時間的日志,按級別排序
LEVEL_PRIORITY = {"DEBUG": 0, "INFO": 1, "WARNING": 2, "ERROR": 3}
def sort_key(log_line):
timestamp = extract_timestamp(log_line)
# 提取日志級別
level = log_line[22:].split()[0]
priority = LEVEL_PRIORITY.get(level, 99)
return (timestamp, priority)
sorted_logs = sorted(logs, key=sort_key)
5.2 自然排序
import re
# 人類期望的排序(自然排序):file1, file2, ..., file10, file11
# 而不是字典序:file1, file10, file11, file2, ...
def natural_sort_key(s):
"""自然排序的key函數(shù)"""
# 將字符串分割為文本和數(shù)字的交替序列
parts = re.split(r'(\d+)', s)
# 將數(shù)字部分轉(zhuǎn)為整數(shù)
return [int(part) if part.isdigit() else part.lower() for part in parts]
files = ["file10.txt", "file1.txt", "file2.txt", "file20.txt", "file11.txt"]
print(sorted(files))
# ['file1.txt', 'file10.txt', 'file11.txt', 'file2.txt', 'file20.txt'] ← 字典序
print(sorted(files, key=natural_sort_key))
# ['file1.txt', 'file2.txt', 'file10.txt', 'file11.txt', 'file20.txt'] ← 自然序
六、總結(jié)
sorted()的key參數(shù)是Python排序系統(tǒng)的精髓,它讓你能按任意規(guī)則排序——從簡單的按長度排,到復雜的多字段組合排序。
?? 核心要點:
sorted()返回新列表,list.sort()原地排序key函數(shù)定義排序依據(jù)——返回什么就按什么排- 元組key實現(xiàn)多級排序——
key=lambda x: (x.a, -x.b) - 穩(wěn)定性——兩次sorted可實現(xiàn)復雜排序
- lambda + key是最常用的排序方式
? 記住:key返回的不是元素本身,而是用于比較的"排序值"。合理使用key,你能排序任何數(shù)據(jù)結(jié)構(gòu)。
到此這篇關(guān)于Python中sorted()排序函數(shù)與自定義排序規(guī)則的文章就介紹到這了,更多相關(guān)Python中sorted()排序與自定義排序內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
pandas dataframe統(tǒng)計填充空值方式
這篇文章主要介紹了pandas dataframe統(tǒng)計填充空值方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-02-02
Python操作csv文件之csv.writer()和csv.DictWriter()方法的基本使用
csv文件是一種逗號分隔的純文本形式存儲的表格數(shù)據(jù),Python內(nèi)置了CSV模塊,可直接通過該模塊實現(xiàn)csv文件的讀寫操作,下面這篇文章主要給大家介紹了關(guān)于Python操作csv文件之csv.writer()和csv.DictWriter()方法的基本使用,需要的朋友可以參考下2022-09-09
解決Pytorch自定義層出現(xiàn)多Variable共享內(nèi)存錯誤問題
這篇文章主要介紹了解決Pytorch自定義層出現(xiàn)多Variable共享內(nèi)存錯誤問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-06-06
Python使用multiprocessing實現(xiàn)一個最簡單的分布式作業(yè)調(diào)度系統(tǒng)
mutilprocess像線程一樣管理進程,這個是mutilprocess的核心,他與threading很是相像,對多核CPU的利用率會比threading好的多,通過本文給大家介紹Python使用multiprocessing實現(xiàn)一個最簡單的分布式作業(yè)調(diào)度系統(tǒng),需要的朋友參考下2016-03-03
python接口自動化測試之接口數(shù)據(jù)依賴的實現(xiàn)方法
這篇文章主要介紹了python接口自動化測試之接口數(shù)據(jù)依賴的實現(xiàn)方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-04-04

