2025年9月2日 星期二

C++/Python3/Go/Rust 關於 list/array/vector 的 sort 在設計上的不同差異

***此篇文章由 Gemini AI 產生*** 在軟體開發中,排序幾乎可以說是最常見的需求之一。然而,不同的程式語言在排序功能的設計上卻有著一些有趣的差異。這篇文章將帶您一探究竟,比較 C++、Python、Go 和 Rust 中 `list`、`array` 或 `vector` 等資料結構的排序(sort)功能,並透過程式碼範例,讓您更深入了解它們在設計上的不同之處。 ### C++:回傳布林值的比較函式 C++ 的 `std::ranges::sort`(以及舊版的 `std::sort`)在自訂排序行為時,需要傳入一個比較函式(Comparison Function),而這個函式必須回傳布林值(`bool`)。 這個比較函式通常接收兩個參數,並在這兩個參數之間進行比較。如果第一個參數應該排在第二個參數之前,則回傳 `true`,否則回傳 `false`。 ```cpp #include #include #include #include struct Person { std::string name; int age; }; int main() { std::vector<Person> people = { {"Alice", 30}, {"Bob", 25}, {"Charlie", 35} }; // 使用 lambda 運算式定義比較函式,按年齡升序排序 std::ranges::sort(people, [](const Person& a, const Person& b) { return a.age < b.age; }); for (const auto& person : people) { std::cout << person.name << " (" << person.age << ")" << std::endl; } return 0; } ``` **輸出結果:** ``` Bob (25) Alice (30) Charlie (35) ``` ### Python:提供 Key Function 提取比較值 Python 的 `list.sort()` 方法則提供了另一種更為簡潔的自訂排序方式。您可以傳入一個名為 `key` 的參數,這個 `key` 參數會接收一個函式,用來從每個元素中提取一個用於比較的「鍵」(key)。 這種設計的好處是,您不需要撰寫一個完整的比較函式,只需要提供一個簡單的函式來告訴 `sort()` 方法要用哪個值來進行排序即可。 ```python class Person: def __init__(self, name, age): self.name = name self.age = age people = [ Person("Alice", 30), Person("Bob", 25), Person("Charlie", 35) ] # 使用 lambda 函式作為 key,按年齡升序排序 people.sort(key=lambda person: person.age) for person in people: print(f"{person.name} ({person.age})") ``` **輸出結果:** ``` Bob (25) Alice (30) Charlie (35) ``` ### Go:回傳 -1, 0, 1 的比較函式 Go 語言的 `slices.SortFunc` 則採用了另一種常見的比較函式設計。您需要傳入一個比較函式,這個函式會回傳一個整數,用來表示兩個元素的相對順序: * **-1**:如果第一個元素應該排在第二個元素之前。 * **0**:如果兩個元素相等。 * **1**:如果第一個元素應該排在第二個元素之後。 ```go package main import ( "fmt" "slices" ) type Person struct { Name string Age int } func main() { people := []Person{ {"Alice", 30}, {"Bob", 25}, {"Charlie", 35}, } // 按年齡升序排序 slices.SortFunc(people, func(a, b Person) int { if a.Age < b.Age { return -1 } if a.Age > b.Age { return 1 } return 0 }) fmt.Println(people) } ``` **輸出結果:** ``` [{Bob 25} {Alice 30} {Charlie 35}] ``` ### Rust:兩種方式,任君挑選 Rust 在排序功能的設計上,可以說是集各家之大成,提供了兩種不同的自訂排序方式: 1. **`sort_unstable_by_key`**:類似於 Python 的 `key` 參數,您可以傳入一個函式來提取用於比較的鍵。 2. **`sort_unstable_by`**:類似於 Go 的比較函式,您可以傳入一個回傳 `Ordering`(一個包含 `Less`、`Equal` 和 `Greater` 三個值的枚舉)的函式。 ```rust #[derive(Debug, Eq, Ord, PartialEq, PartialOrd)] struct Person { name: String, age: u32, } fn main() { let mut people = vec![ Person { name: "Alice".to_string(), age: 30 }, Person { name: "Bob".to_string(), age: 25 }, Person { name: "Charlie".to_string(), age: 35 }, ]; // 1. 使用 sort_unstable_by_key 按年齡升序排序 people.sort_unstable_by_key(|p| p.age); println!("{:?}", people); // 2. 使用 sort_unstable_by 按年齡降序排序 people.sort_unstable_by(|a, b| b.age.cmp(&a.age)); println!("{:?}", people); } ``` **輸出結果:** ``` [Person { name: "Bob", age: 25 }, Person { name: "Alice", age: 30 }, Person { name: "Charlie", age: 35 }] [Person { name: "Charlie", age: 35 }, Person { name: "Alice", age: 30 }, Person { name: "Bob", age: 25 }] ``` ### 總結 | 語言 | 方法 | 回傳值 | | --- | --- | --- | | C++ | 比較函式 | `bool` | | Python | Key Function | 任何可比較的值 | | Go | 比較函式 | `-1`, `0`, `1` | | Rust | Key Function 或比較函式 | 任何可比較的值或 `Ordering` | 從以上比較可以看出,雖然排序是一個基本的功能,但不同的程式語言在 API 設計上卻有著不同的哲學和取捨。C++ 提供了最底層的控制,但也相對繁瑣;Python 則追求簡潔與易用性;Go 則採用了傳統的「三向比較」;而 Rust 則提供了最靈活的選擇,讓開發者可以根據自己的需求選擇最適合的方式。 希望這篇文章能幫助您更深入地了解不同程式語言在排序功能設計上的差異,並在未來的開發工作中,選擇最適合您需求的排序方式。