[英]Sorting strings with numerical digits in it
我有像7X1234 XY1236 NM1235
这样的字符串。 我想使用最后4位数字对这些字符串进行排序,只忽略最初的两个字母。 此外,我想比较这些数字,看看它们是否是连续的。
实现这一目标的一种方法我可以想到的是将这些字符串在字母和数字之间分割为( 7X and 1234
),并且将词典数字字符串转换为int并对其进行处理。 但是,如何在数字字符串进行排序并在C++
中进行比较时,如何将字母表部分再次与数字部分相关联,即数字部分再次为7X
,最后为1234
?
总之,如果我有7X1234 XY1236 NM1235 BV1238
我需要得到7X1234 NM1235 XY1236 BV1238
我没有详细说明我想知道字符串的数字部分是否是连续的。 现在,当我像1234 1236 1235 1238这样的内注时,我会做类似下面的事情
std::vector<int> sortedDigits{1234 1235 1236 1238};
int count = 1;
int pos = 0;
std::vector<std::pair<int, int> > myVec;
myVec.push_back(std::make_pair(sortedDigits[pos], count));
for(size_t i = 1; i < sortedDigits.size(); ++i)
{
if(sortedDigits[i] != (sortedDigits[i-1] + 1))
{
count = 1;
myVec.push_back(std::make_pair(sortedDigits[i], count) );
++pos;
}
else
{
sortedDigits[pos].second = ++count;
}
}
所以最后我得到(1234, 3)
和(1238, 1)
当字符串出现时,我不知道怎样才能得到这样的东西?
由于数字的字符编码值的排序顺序与它们所代表的数字的顺序相同,因此您可以对最后四位数进行字符串比较:
#include <cstring>
#include <string>
// Requires: a.size() >= 2, b.size() >= 2
bool two_less(std::string const & a, std::string const & b)
{
return std::strcmp(a.data() + 2, b.data() + 2) < 0;
}
现在使用sort
with predicate:
#include <algorithm>
#include <vector>
std::vector<std::string> data { "7X1234", "YX1236" };
std::sort(data.begin(), data.end(), two_less);
在C ++ 11中,特别是如果你没有重复使用它,你也可以在sort
调用中直接使用lambda:
std::sort(data.begin(), data.end(),
[](std::string const & a, std::string const & b)
{ return std::strcmp(a.data() + 2, b.data() + 2) < 0; });
然后,如果需要改变它,您甚至可以将数字“2”设为捕获的变量。
使用qsort并提供一个比较器函数,该函数索引到字符串的开头加上偏移量为2,而不是直接从字符串的开头开始。
例如,您的比较器功能可能如下所示:
int compare (const void * a, const void * b)
{
char * a_cmp = ((char *)a)+2;
char * b_cmp = ((char *)b)+2;
return strcmp(a_cmp, b_cmp);
}
您应该创建一个封装字符串的类,该类具有int
和string字段。 此类可以使比较运算符重载。
class NumberedString
{
private:
int number;
string originalString;
public:
NumberedString(string original) { ... }
friend bool operator> (NumberedString &left, NumberedString &right);
friend bool operator<=(NumberedString &left, NumberedString &right);
friend bool operator< (NumberedString &left, NumberedString &right);
friend bool operator>=(NumberedString &left, NumberedString &right);
};
你可以定义你的比较器
bool mycomparator(const std::string& a, const std::string& b) {
return a.substr(2) < b.substr(2);
}
然后你可以对你的std::vector<std::string>
mycomparator
,将mycomparator
作为第三个参数传递。
在C ++ 11中,这也是一个匿名lambda非常适合的情况......
#include <vector>
#include <algorithm>
#include <string>
#include <iostream>
int main(int argc, const char *argv[])
{
std::vector<std::string> data = {"7X1234", "XY1236", "NM1235", "BV1238"};
std::sort(data.begin(), data.end(),
[](const std::string& a, const std::string& b) {
return a.substr(2) < b.substr(2);
});
for (auto x : data) {
std::cout << x << std::endl;
}
return 0;
}
如果您100%确定数组中的字符串是XX9999
格式,则可以使用
return strncmp(a.data()+2, b.data()+2, 4) < 0;
这样更有效,因为不需要任何内存分配来进行比较。
使用std::map<int, std::string>
,使用int值作为键,将相应的字符串作为值。 然后,您可以简单地遍历地图并检索字符串; 它们已按排序顺序排列。
这样的事情怎么样:
std::string str[] = { "7X1234", "XY1236", "NM1235" };
std::map<int, std::string> m;
for(s : str)
{
std::ostringstream ss(s.substr(2));
int num;
ss >> num;
m[num] = s;
}
for(i : m)
{
std::cout << i->second << " ";
}
std::cout << std::endl;
我只是键入了这个,所以可能存在轻微的错别字/错误,但原则应该有效。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.