对带有数字的字符串进行排序

时间:2013-08-09 09:16:29

标签: c++ string

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

实现这一目标的一种方法我可以想到的是将这些字符串在字母和数字之间拆分为(7X and 1234),并将词典数字字符串转换为int并对其进行处理。但是,如何在7X中对数字字符串进行排序和比较时,如何将字母表部分再次与数字部分相关联,该部分是如何在1234处再次加C++前缀? / p>

总之,如果我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)

我不知道当有字符串时我怎么能得到这样的东西?

7 个答案:

答案 0 :(得分:11)

由于数字的字符编码值的排序顺序与它们所代表的数字相同,因此您可以对最后四位数进行字符串比较:

#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”设为捕获的变量。

答案 1 :(得分: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);
}

答案 2 :(得分:1)

你可以像这样制作结构

struct combined{
    string alph;
    int numeral;
};

将这些放在c ++标准容器中

并使用algoritm与用户定义的比较对象。

答案 3 :(得分:1)

您应该创建一个封装字符串的类,其中包含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);
};

答案 4 :(得分:1)

您可以定义比较器

bool mycomparator(const std::string& a, const std::string& b) {
    return a.substr(2) < b.substr(2);
}

然后您可以将std::vector<std::string>传递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;

效率更高,因为不需要任何内存分配来进行比较。

答案 5 :(得分:0)

使用std::map<int, std::string>,使用int值作为键,将相应的字符串作为值。然后,您可以简单地遍历地图并检索字符串;它们已按排序顺序排列。

答案 6 :(得分:0)

这样的事情怎么样:

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;

我刚输入此内容,因此可能存在较小的错别字/错误,但原则应该有效。