sort 和 sort!的区别

本文介绍了Ruby中的sort方法及其变种sort!,详细解释了如何使用sort方法对数组进行升序和降序排列,并展示了如何利用符号<=>来进行元素间的比较。此外,还对比了sort与sort!在数组修改方面的不同。

sort方法用于数组排序,返回排序后的新数组(排序的比较用 <=> 运算符)
a = [“d”, “a”, “e”, “c”, “b”]
b = [ 6, 3, 5, 2, 7 ]
a.sort => [“a”, “b”, “c”, “d”, “e”]
a.sort { |x,y| y <=> x } => [“e”, “d”, “c”, “b”, “a”]
a.sort { |x,y| x <=> y } => [“a”, “b”, “c”, “d”, “e”]
b.sort => [2, 3, 5, 6, 7]
b.sort { |x,y| y <=> x } => [7, 6, 5, 3, 2]
b.sort { |x,y| x <=> y } => [2, 3, 5, 6, 7]

sort! 和 sort 效果一样,默认都使用 <=>比较,他们的区别在于:
sort! 可能会改变原先的数组,所以加个感叹号提醒;
sort 返回的是新数组,没对原先的数组进行修改;
在ruby中有很多加了感叹号的函数,这意味着对函数操作的对象进行了状态更改。

a.sort! => [“a”, “b”, “c”, “d”, “e”]
b.sort! => [2, 3, 5, 6, 7]
a => [“a”, “b”, “c”, “d”, “e”]
b => [2, 3, 5, 6, 7]

<think>我们正在讨论C++中的`std::sort``ranges::sort`。根据引用内容,我们可以总结以下几点:1.**语法简洁性**:`ranges::sort`在C++20中引入,其语法更简洁。例如,`std::sort`需要传递开始结束迭代器,而`ranges::sort`可以直接传递整个范围。-示例:`std::sort(vec.begin(),vec.end());`vs`ranges::sort(vec);`[^1][^2]2.**自定义比较**:两者都支持自定义比较函数或Lambda表达式。但`ranges::sort`在调用时可以直接将自定义比较函数作为第二个参数,而`std::sort`同样如此。不过,`ranges::sort`在范围传递上更直接。-示例:`ranges::sort(numbers,[](inta,intb){returna%3<b%3;});`[^2]3.**安全性增强**:`ranges::sort`属于C++20的范围库,设计上更注重安全性,比如可以避免迭代器不匹配的问题。4.**返回值**:`std::sort`没有返回值(返回`void`),而`ranges::sort`返回一个迭代器,指向排序后范围的末尾(即结束迭代器)。但通常我们不需要使用这个返回值。5.**支持投影(Projection)**:`ranges::sort`支持投影参数,这是一个强大的功能。投影允许在排序之前对元素进行转换,而无需在比较函数中显式编写转换逻辑。-例如,我们可以按字符串长度排序而不改变比较函数:`ranges::sort(vec,{},&std::string::size);`这里第二个参数是自定义比较(这里使用默认的`std::less{}`),第三个参数是投影(取字符串长度)。6.**约束**:`ranges::sort`要求范围满足`std::ranges::random_access_range`并且元素类型满足`std::permutable``std::sortable`。而`std::sort`要求随机访问迭代器。下面我们详细说明:###1.基本用法比较-**`std::sort`**(传统方式):```cpp#include<algorithm>#include<vector>std::vector<int>vec={5,3,1,4,2};std::sort(vec.begin(),vec.end());//升序排序```-**`ranges::sort`**(C++20):```cpp#include<algorithm>#include<vector>#include<ranges>//C++20范围库std::vector<int>vec={5,3,1,4,2};std::ranges::sort(vec);//直接对vec排序,默认升序```###2.自定义比较函数两者都支持:```cpp//使用std::sortstd::sort(vec.begin(),vec.end(),[](inta,intb){returna>b;//降序});//使用ranges::sortstd::ranges::sort(vec,[](inta,intb){returna>b;//降序});```###3.投影(Projection)功能这是`ranges::sort`独有的强大特性。投影允许我们在比较之前对每个元素进行转换,而无需修改比较函数。例如,我们有一个`Person`结构体,我们想按年龄排序:```cppstructPerson{std::stringname;intage;};std::vector<Person>people={{"Alice",30},{"Bob",25},{"Charlie",35}};//使用ranges::sort按年龄升序排序std::ranges::sort(people,{},&Person::age);//或者更明确地写比较规则(默认是升序,所以下面等同于上面)std::ranges::sort(people,std::less{},&Person::age);//如果我们想按年龄降序,可以:std::ranges::sort(people,std::greater{},&Person::age);```这里第二个参数是比较函数对象(我们使用`std::less{}`或`std::greater{}`),第三个参数是投影(指向成员的指针或可调用对象)。如果我们使用Lambda作为投影:```cppstd::ranges::sort(people,std::greater{},[](constPerson&p){returnp.age;});```###4.返回值`ranges::sort`返回一个迭代器(通常是范围的末尾迭代器),而`std::sort`无返回值。###5.性能两者在性能上应该没有显著差异,因为底层算法相同(通常是快速排序的变体)。但是,由于投影功能,`ranges::sort`可能在某些情况下生成更高效的代码(因为投影可能被内联优化)。###总结-**`std::sort`**:传统的排序算法,需要显式传递迭代器范围。-**`ranges::sort`**:C++20引入,语法更简洁,支持投影,返回迭代器,更安全。建议在新的C++20项目中使用`ranges::sort`,因为它更简洁且功能更强大。但在需要兼容旧标准的情况下,使用`std::sort`。[^1]:引用[1]中提到了`std::sort``ranges::sort`的基本用法。[^2]:引用[2]中强调了`ranges::sort`的语法简洁性自定义比较的使用。§§相关问题§§1.C++20范围库中还有哪些常用的算法?2.如何在`ranges::sort`中使用自定义投影函数?3.`ranges::sort``std::sort`在性能上有何差异?</think>### C++ `ranges::sort` 与 `std::sort` 的区别及用法比较 #### 1. **基本语法差异** - **`std::sort`** (传统方式): 需显式传递迭代器范围 ```cpp std::vector<int> vec = {5, 3, 1, 4, 2}; std::sort(vec.begin(), vec.end()); // 默认升序排序[^1] ``` - **`ranges::sort`** (C++20 新特性): 直接传递容器或范围视图 ```cpp std::ranges::sort(vec); // 简洁语法,无需迭代器[^2] ``` #### 2. **自定义比较函数的实现** - **共同点**:两者均支持 Lambda 或自定义比较器 ```cpp // std::sort 自定义比较 std::sort(vec.begin(), vec.end(), [](int a, int b) { return a > b; // 降序排序 }); // ranges::sort 自定义比较 std::ranges::sort(vec, [](int a, int b) { return a % 3 < b % 3; // 按模3余数排序[^2] }); ``` - **区别**:`ranges::sort` 支持 **投影(Projection)** 参数: ```cpp struct Person { std::string name; int age; }; std::vector<Person> people = {{"Alice", 30}, {"Bob", 25}}; // 按年龄排序(无需在Lambda中写 person.age) std::ranges::sort(people, {}, &Person::age); // 等价于: std::ranges::sort(people, std::less{}, &Person::age); ``` #### 3. **核心优势对比** | 特性 | `std::sort` | `ranges::sort` (C++20) | |---------------------|--------------------------------|----------------------------------| | **语法简洁性** | 需手动指定 `begin()`/`end()` | 直接操作整个容器 (`ranges::sort(vec)`) [^2] | | **范围安全性** | 可能因迭代器不匹配导致未定义行为 | 编译时范围检查,避免迭代器错误 | | **投影支持** | 不支持 | 可通过投影简化复杂数据排序 | | **返回值** | `void` | 返回排序后的子范围迭代器 | | **函数式编程兼容性**| 较低 | 与 `ranges::view` 无缝协作 | #### 4. **底层实现与性能** - **算法相同**:两者均基于 **内省排序**(快速排序+堆排序混合) - **性能差异**:实际运行效率几乎相同,但 `ranges::sort` 的投影功能可能减少临时对象创建: ```cpp // 传统方式需创建临时键 std::sort(people.begin(), people.end(), [](const Person& a, const Person& b) { return a.age < b.age; // 可能复制Person对象 }); // ranges::sort 避免复制 std::ranges::sort(people, {}, &Person::age); // 仅访问成员 ``` #### 5. **使用建议** - **优先 `ranges::sort` 当**: - 使用 C++20 或更新标准 - 需要简洁语法范围安全性 - 处理嵌套数据结构(利用投影) - **沿用 `std::sort` 当**: - 维护旧代码(C++11/14/17) - 需要显式控制子范围排序(如 `std::sort(vec.begin()+1, vec.end()-1)`) > **关键总结**:`ranges::sort` 不是替代品而是**增强**,它在保持相同性能的前提下,通过现代C++特性提供更安全、更简洁的接口[^1][^2]。 --- ### 相关问题 1. C++20 范围库中除 `ranges::sort` 外还有哪些常用算法? 2. 如何在 `ranges::sort` 中组合使用投影自定义比较函数? 3. `ranges::sort` 与并行排序(如 `std::sort(std::execution::par, ...)`)如何协同工作?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值