对包含数字的字符串进行排序

Sorting strings with numerical digits in it

本文关键字:排序 字符串 包含 数字      更新时间:2023-10-16

我有类似7X1234 XY1236 NM1235的字符串。我想使用最后4个数字对这些字符串进行排序,只忽略开头的两个字母。此外,我想比较这些数字,看看它们是否是连续的。

我能想到的实现这一点的一种方法是将这些字符串在字母和数字之间拆分为(7X and 1234),并将数字字符串进行词法转换为int并进行处理。但是,我如何将字母部分再次与数字部分相关联,也就是说,当在C++中对数字字符串进行排序和比较时,如何在末尾将7X再次前缀为1234

简而言之,如果我有7X1234 XY1236 NM1235 BV1238,我需要获得7X1234 NM1235 XY1236 BV1238

我没有详细说明我想知道字符串的数字部分是否是连续的。现在,当我只有像1234 1236 1235 1238这样的int时,我会在下面做一些事情

            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

#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);
}

例如,您可以制作这样的结构

struct combined{
    string alph;
    int numeral;
};

把这些放在一个c++标准容器中

并将这种算法与用户定义的比较对象一起使用。

您应该创建一个封装字符串的类,该类具有int和字符串字段。此类可以重载比较运算符。

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);
}

那么您可以通过mycomparator作为第三个参数对std::vector<std::string>进行排序。

在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;

我刚刚输入了这个,所以可能会有一些小的打字错误,但原则应该有效。