通过子串排序字符串向量?

时间:2018-02-15 16:51:20

标签: c++

我有一个包含许多相同形式的字符串的向量:

'12345 QWERTY'
'23456 ASDFGH'
'34567 ZXCVBN'

我需要按代码(int类型)和名称(字符串类型)对它们进行排序。我正在考虑使用.substr()函数来忽略这些数字。有没有办法在sort函数中使用它?

尝试创建一个映射函数来赞美'sort()':

bool mapFunc(string a, string b) 
{
return a.substr(6) < b.substr(6));
}

插入排序功能:

sort(begin, end, mapFunc);

其中'begin'和'end'都是指向vector的开头和结尾的迭代器。

如果我在这里犯了任何错误,请纠正我。)

6 个答案:

答案 0 :(得分:3)

通过将自定义谓词传递给std::sort(),您处于正确的轨道上。你只需要更多地充实它:

void split(const string &s, int &code, string &name) {
    size_t idx = s.find(' ');
    code = stoi(s.substr(0, idx));
    name = s.substr(idx+1);
}

bool mapFunc(const string &a, const string &b) {
    int code1, code2; 
    string name1, name2; 
    split(a, code1, name1);
    split(b, code2, name2);
    if (code1 == code2)
        return name1 < name2; 
    return code1 < code2;
}

这将首先按照数字代码对矢量项进行排序,并仅按名称对具有相同代码值的项进行排序。

答案 1 :(得分:2)

您可以使用functor(函数对象):

struct Compare_By_Number
{
  bool operator()(const std::string& a, const std::string& b) const
  {
    std::istringstream a_input_stream(a);
    std::istringstream b_input_stream(b);
    int a_value, b_value;
    a_input_stream >> a_value;
    b_input_stream >> b_value;
    return a_value < b_value;
  }
};

然后,您可以根据the std::sort example传递函数的实例。

编辑1:独立功能
另一种方法是将代码放在独立函数中并传递函数:

bool Order_By_Number(const std::string& a, const std::string& b)
{
    std::istringstream a_input_stream(a);
    std::istringstream b_input_stream(b);
    int a_value, b_value;
    a_input_stream >> a_value;
    b_input_stream >> b_value;
    return a_value < b_value;
}

std::vector<std::string> database;
//...
std::sort(database.begin(), database.end(), Order_By_Number);

如果第一个参数位于您订购的第二个参数之前,则基本概念是返回true

答案 2 :(得分:1)

我认为使用std::lexicographical_compare提取子字符串会更有效。

std::lexicographical_compare的作用是比较 到位 的子字符串,因此您无需支付将其复制出来的费用。

这样的事情:

std::vector<std::string> v
{
    "12345 QWERTY",
    "23456 ASDFGH",
    "34567 ZXCVBN",
};

std::sort(std::begin(v), std::end(v), [](std::string const& a, std::string const& b){
    return std::lexicographical_compare(std::begin(a), std::begin(a) + 5, std::begin(b), std::begin(b) + 5);
});

std::cout << "By first column" << '\n';
for(auto const& s: v)
    std::cout << s << '\n';

std::sort(std::begin(v), std::end(v), [](std::string const& a, std::string const& b){
    return std::lexicographical_compare(std::begin(a) + 6, std::end(a), std::begin(b) + 6, std::end(b));
});

如果您要做很​​多这样的事情,那么您可以将它包装在一个特殊的比较器中:

struct substring_compare
{
    std::size_t from;
    std::size_t len;

    substring_compare(std::size_t from, std::size_t len)
    : from(from), len(len) {}

    bool operator()(std::string const& a, std::string const& b) const
    {
        // sanity checks
        assert(from + len <= a.size());
        assert(from + len <= b.size());

        auto beg_a = std::begin(a) + from;
        auto end_a = beg_a + len;

        auto beg_b = std::begin(b) + from;
        auto end_b = beg_a + len;

        return std::lexicographical_compare(beg_a, end_a, beg_b, end_b);
    }
};

int main()
{
    std::vector<std::string> v
    {
        "12345 QWERTY",
        "23456 ASDFGH",
        "34567 ZXCVBN",
    };

    // start at position 0, comparing 5 characters
    std::sort(std::begin(v), std::end(v), substring_compare(0, 5));

    std::cout << "By first column" << '\n';
    for(auto const& s: v)
        std::cout << s << '\n';

    // start at position 6, comparing 6 characters
    std::sort(std::begin(v), std::end(v), substring_compare(6, 6));

    std::cout << "By second column" << '\n';
    for(auto const& s: v)
        std::cout << s << '\n';
}

<强>输出:

By first column
12345 QWERTY
23456 ASDFGH
34567 ZXCVBN

By second column
23456 ASDFGH
12345 QWERTY
34567 ZXCVBN

答案 3 :(得分:1)

您可以使用std::pair提供的现有功能(比较运算符)。所以实现转换功能:

std::pair<int,std::string> convert( const std::string &str )
{
     int id = 0;
     std::string name;
     std::istringstream is( str );
     is >> id >> name;
     return std::make_pair( id, name );
}

然后你的比较器功能很简单:

bool compare( const std::string &s1, const std::string &s2 )
{
     return convert( s1 ) < convert( s2 );
}

答案 4 :(得分:0)

你最好有std::vector<std::pair<int, string>>来消除这些并发症。 否则,您应该创建比较函数并传递子字符串。

答案 5 :(得分:0)

要设置问题,我们有一个字符串向量:

vector<string>myVec;

vector<string>::iterator vecBegin=myVec.begin(), vecBegin=myVec.end();

尝试创建一个映射函数来赞美'sort()':

bool mapFunc(string a, string b) 
{
return a.substr(6) < b.substr(6));
}

插入排序功能:

sort(vecBegin, vecEnd, mapFunc);

其中'vecBegin'和'vecEnd'都是指向向量开头和结尾的迭代器。

这将通过子串对字符串向量进行排序。可以使用迭代器访问该向量:

vector<string>::iterator currentVec;
for (currentVec=vecBegin; currentVec<vecEnd; ++currentVec) 
{
// Do things
}