如何在sort函数中用substr对string类型vector按子串排序?
你的思路完全可行,这样实现按code和name排序没问题!
首先要肯定你的想法:C++的sort函数本身就支持传入自定义的比较逻辑,不管是单独写映射函数提取排序键,还是直接在比较逻辑里处理字符串,都是完全合理的方案。下面我给你拆解几种具体的实现方式,你可以根据自己的场景选择:
1. 直接在sort的lambda里处理字符串(最直观)
如果你的字符串格式是固定的(比如类似"123_alice"这种,数字code在前、字符串name在后,用下划线分隔),可以直接在sort的第三个参数里写lambda表达式,当场提取code和name再做比较:
#include <vector> #include <algorithm> #include <string> #include <iostream> using namespace std; int main() { vector<string> strVec = {"2_bob", "1_alice", "3_charlie", "2_alice"}; sort(strVec.begin(), strVec.end(), [](const string& a, const string& b) { // 提取a的code和name size_t splitPosA = a.find('_'); int codeA = stoi(a.substr(0, splitPosA)); string nameA = a.substr(splitPosA + 1); // 提取b的code和name size_t splitPosB = b.find('_'); int codeB = stoi(b.substr(0, splitPosB)); string nameB = b.substr(splitPosB + 1); // 排序规则:先按code升序,code相同则按name升序 if (codeA != codeB) { return codeA < codeB; } else { return nameA < nameB; } }); // 验证结果 for (const auto& s : strVec) { cout << s << endl; } return 0; }
这种方式的优点是逻辑直接,不需要额外的辅助函数,适合数据量不大的场景。
2. 封装映射函数提取排序键(更易维护)
如果你的字符串提取逻辑比较复杂,或者需要在多个地方复用,可以把提取code和name的逻辑封装成一个映射函数,然后在sort的比较lambda里调用它:
#include <vector> #include <algorithm> #include <string> #include <iostream> #include <stdexcept> using namespace std; // 定义排序键的结构体,存储提取后的code和name struct SortKey { int code; string name; }; // 映射函数:把输入字符串转换成SortKey SortKey getSortKey(const string& s) { size_t splitPos = s.find('_'); // 先做格式校验,避免非法字符串导致崩溃 if (splitPos == string::npos) { throw invalid_argument("字符串格式错误:缺少分隔符"); } try { int code = stoi(s.substr(0, splitPos)); return {code, s.substr(splitPos + 1)}; } catch (const invalid_argument&) { throw invalid_argument("字符串格式错误:code不是有效整数"); } } int main() { vector<string> strVec = {"2_bob", "1_alice", "3_charlie", "2_alice"}; sort(strVec.begin(), strVec.end(), [](const string& a, const string& b) { SortKey keyA = getSortKey(a); SortKey keyB = getSortKey(b); if (keyA.code != keyB.code) { return keyA.code < keyB.code; } return keyA.name < keyB.name; }); for (const auto& s : strVec) { cout << s << endl; } return 0; }
这种方式把提取逻辑和比较逻辑分开,代码更清晰,也方便后续修改提取规则。
3. 预处理排序键(大数据量优化)
如果你的vector里元素特别多,每次比较都调用substr和stoi会有重复开销,这时候可以先把所有字符串的排序键预处理出来,再通过索引排序来优化性能:
#include <vector> #include <algorithm> #include <string> #include <iostream> #include <numeric> // 用于iota using namespace std; struct SortKey { int code; string name; }; SortKey getSortKey(const string& s) { size_t splitPos = s.find('_'); return {stoi(s.substr(0, splitPos)), s.substr(splitPos + 1)}; } int main() { vector<string> strVec = {"2_bob", "1_alice", "3_charlie", "2_alice"}; // 预处理所有排序键 vector<SortKey> keys; keys.reserve(strVec.size()); for (const auto& s : strVec) { keys.push_back(getSortKey(s)); } // 创建索引数组,初始为0,1,2,... vector<int> indices(strVec.size()); iota(indices.begin(), indices.end(), 0); // 根据索引对应的排序键排序 sort(indices.begin(), indices.end(), [&keys](int i, int j) { if (keys[i].code != keys[j].code) { return keys[i].code < keys[j].code; } return keys[i].name < keys[j].name; }); // 根据排序后的索引重新生成原vector vector<string> sortedVec; sortedVec.reserve(strVec.size()); for (int idx : indices) { sortedVec.push_back(strVec[idx]); } // 替换原vector strVec.swap(sortedVec); for (const auto& s : strVec) { cout << s << endl; } return 0; }
这种方式只做一次字符串提取和转换,比较时直接用预处理好的键,性能会好很多。
注意事项
- 一定要确保你的字符串格式是固定的,如果存在格式不合法的字符串(比如没有分隔符、code不是整数),最好加校验逻辑(比如第二个例子里的异常处理),避免程序崩溃。
- 如果你的排序规则是降序,只需要把比较里的
<改成>即可。
内容的提问来源于stack exchange,提问作者b._.rett
相关产品推荐
相关产品推荐

