Python中sorted()排序函數(shù)與自定義排序規(guī)則
一、開篇:排序——數(shù)據(jù)處理的基本功
排序是編程中最常見的操作之一。Python提供了兩個(gè)排序工具:list.sort()(原地排序)和sorted()(返回新排序結(jié)果)。其中sorted()更靈活、更通用——它能排序任何可迭代對(duì)象,還能自定義排序規(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ù)不變,可用于任何可迭代對(duì)象 # list.sort() → 原地排序,不返回新列表,只能用于列表
?? sorted()的核心優(yōu)勢(shì)在于它的key參數(shù)——讓你能按任意規(guī)則排序,這個(gè)參數(shù)是Python排序系統(tǒng)的靈魂。
二、sorted()的基本參數(shù)
2.1 三個(gè)參數(shù)詳解
# sorted(iterable, key=None, reverse=False) # iterable: 要排序的可迭代對(duì)象 # key: 排序依據(jù)的函數(shù)(接收每個(gè)元素,返回用于比較的值) # 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"] # 默認(rèn)排序——按Unicode碼點(diǎn)(大寫字母在小寫字母前) print(sorted(words)) # ['Cherry', 'Elderberry', 'apple', 'banana', 'date'] # 按字母順序(忽略大小寫) print(sorted(words, key=str.lower)) # ['apple', 'banana', 'Cherry', 'date', 'Elderberry'] # 按單詞長(zhǎng)度排序 print(sorted(words, key=len)) # ['date', 'apple', 'banana', 'Cherry', 'Elderberry']
2.2 key參數(shù)的詳解
# ?? key函數(shù)的規(guī)則:
# 1. key接收一個(gè)參數(shù)(序列中的每個(gè)元素)
# 2. key返回一個(gè)用于比較的值
# 3. 排序根據(jù)key的返回值進(jìn)行(不是原始元素)
# 4. 原始元素不變——只是排序的依據(jù)變了
# 絕對(duì)值排序
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ù)字大小排!
# 按時(shí)間排序
times = ["2024-03-15", "2023-12-01", "2024-01-20", "2023-06-10"]
print(sorted(times)) # 字符串比較恰好對(duì)日期格式有效!
# ['2023-06-10', '2023-12-01', '2024-01-20', '2024-03-15']
三、lambda作為key——最常用的排序方式
3.1 按字典字段排序
# ?? 排序字典列表——職場(chǎng)中最常用的技能
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": "市場(chǎng)部"},
{"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)]
# 按年齡排序,同年齡按薪資降序(多級(jí)排序)
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 多級(jí)排序
# ?? 多級(jí)排序:key返回一個(gè)元組
# 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
# 市場(chǎng)部 - 趙六: ¥18000
# ?? 技巧:降序字段用負(fù)號(hào)
# 數(shù)字降序:-e["salary"](注意:這只對(duì)數(shù)字有效)
# 字符串降序:沒法用負(fù)號(hào),需要分兩次排序或用functools.cmp_to_key
# 多級(jí)排序的另一種方法:多次sorted()(利用穩(wěn)定性)
# Python的排序是穩(wěn)定的——相同key的元素保持原來的相對(duì)順序
# 先按次要key排,再按主要key排
result = sorted(employees, key=lambda e: e["salary"], reverse=True)
result = sorted(result, key=lambda e: e["department"])
# 結(jié)果:同一部門內(nèi),按薪資降序
四、高級(jí)排序技巧
4.1 使用operator模塊
from operator import itemgetter, attrgetter, methodcaller
# itemgetter——獲取字典的指定字段(相當(dāng)于lambda e: e["key"])
# 比lambda稍快一些,而且更簡(jiǎn)潔
by_department = sorted(employees, key=itemgetter("department"))
print([e["department"] for e in by_department])
# itemgetter多級(jí)排序
by_dept_salary = sorted(employees, key=itemgetter("department", "salary"))
# attrgetter——獲取對(duì)象的屬性
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 自定義對(duì)象的排序
from functools import total_ordering
# 方法一:實(shí)現(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("寫報(bào)告", 2, "2024-06-15"),
Task("修復(fù)Bug", 1, "2024-06-10"),
Task("開會(huì)", 2, "2024-06-12"),
Task("代碼審查", 1, "2024-06-08"),
]
print(sorted(tasks))
# [Task(代碼審查, pri=1, due=2024-06-08), Task(修復(fù)Bug, pri=1, due=2024-06-10),
# Task(開會(huì), pri=2, due=2024-06-12), Task(寫報(bào)告, pri=2, due=2024-06-15)]
# 方法二:使用key(更靈活,不修改類)
tasks_sorted = sorted(tasks, key=lambda t: (t.priority, t.due_date))
五、實(shí)戰(zhàn)案例
5.1 日志按時(shí)間排序
# 場(chǎng)景:排序雜亂的日志條目
logs = [
"[2024-03-15 14:30:22] ERROR 數(shù)據(jù)庫連接失敗",
"[2024-03-15 14:25:10] INFO 服務(wù)器啟動(dòng)",
"[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):
"""從日志行中提取時(shí)間戳"""
return log_line[1:20] # 提取 "[2024-03-15 14:30:22]" 中的時(shí)間
sorted_logs = sorted(logs, key=extract_timestamp)
for log in sorted_logs:
print(log)
# 按時(shí)間正序排列
# 對(duì)于同時(shí)間的日志,按級(jí)別排序
LEVEL_PRIORITY = {"DEBUG": 0, "INFO": 1, "WARNING": 2, "ERROR": 3}
def sort_key(log_line):
timestamp = extract_timestamp(log_line)
# 提取日志級(jí)別
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ī)則排序——從簡(jiǎn)單的按長(zhǎng)度排,到復(fù)雜的多字段組合排序。
?? 核心要點(diǎn):
sorted()返回新列表,list.sort()原地排序key函數(shù)定義排序依據(jù)——返回什么就按什么排- 元組key實(shí)現(xiàn)多級(jí)排序——
key=lambda x: (x.a, -x.b) - 穩(wěn)定性——兩次sorted可實(shí)現(xiàn)復(fù)雜排序
- lambda + key是最常用的排序方式
? 記?。?/strong>key返回的不是元素本身,而是用于比較的"排序值"。合理使用key,你能排序任何數(shù)據(jù)結(jié)構(gòu)。
到此這篇關(guān)于Python中sorted()排序函數(shù)與自定義排序規(guī)則的文章就介紹到這了,更多相關(guān)Python中sorted()排序與自定義排序內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Python中sorted()函數(shù)之排序的利器詳解
- Python中sorted()函數(shù)的強(qiáng)大排序技術(shù)實(shí)例探索
- 關(guān)于Python排序sort()函數(shù)和sorted()函數(shù)
- Python中排序函數(shù)sorted()函數(shù)的使用實(shí)例
- python列表排序用?sort()和sorted()的區(qū)別
- Python中sorted()排序與字母大小寫的問題
- python排序函數(shù)sort()與sorted()的區(qū)別
- Python中利用sorted()函數(shù)排序的簡(jiǎn)單教程
相關(guān)文章
pandas dataframe統(tǒng)計(jì)填充空值方式
這篇文章主要介紹了pandas dataframe統(tǒng)計(jì)填充空值方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-02-02
Python操作csv文件之csv.writer()和csv.DictWriter()方法的基本使用
csv文件是一種逗號(hào)分隔的純文本形式存儲(chǔ)的表格數(shù)據(jù),Python內(nèi)置了CSV模塊,可直接通過該模塊實(shí)現(xiàn)csv文件的讀寫操作,下面這篇文章主要給大家介紹了關(guān)于Python操作csv文件之csv.writer()和csv.DictWriter()方法的基本使用,需要的朋友可以參考下2022-09-09
解決Pytorch自定義層出現(xiàn)多Variable共享內(nèi)存錯(cuò)誤問題
這篇文章主要介紹了解決Pytorch自定義層出現(xiàn)多Variable共享內(nèi)存錯(cuò)誤問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-06-06
Python使用multiprocessing實(shí)現(xiàn)一個(gè)最簡(jiǎn)單的分布式作業(yè)調(diào)度系統(tǒng)
mutilprocess像線程一樣管理進(jìn)程,這個(gè)是mutilprocess的核心,他與threading很是相像,對(duì)多核CPU的利用率會(huì)比threading好的多,通過本文給大家介紹Python使用multiprocessing實(shí)現(xiàn)一個(gè)最簡(jiǎn)單的分布式作業(yè)調(diào)度系統(tǒng),需要的朋友參考下2016-03-03
python接口自動(dòng)化測(cè)試之接口數(shù)據(jù)依賴的實(shí)現(xiàn)方法
這篇文章主要介紹了python接口自動(dòng)化測(cè)試之接口數(shù)據(jù)依賴的實(shí)現(xiàn)方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-04-04

