0

I have a vector which contains alpha numeric string and I want to sort the vector based on the numeric value.

For example, if my vector contains these values:

name0 name20 name15 name3 name10, my sorted vector should look like this:

name0 name3 name10 name15 namw20.

Can anyone please help how to do this..? Here is my complete code:

#include<vector>

#include<string>
#include <cstdlib>

#include <algorithm>
#include <iostream>
using namespace std;

int main()
{
        vector<string> temp;
        temp.push_back("name0");
        temp.push_back("name20");
        temp.push_back("name15");
        temp.push_back("name3");
        temp.push_back("name10");

        sort(temp.begin(), temp.end());


        for (vector<string>::size_type i = 0; i!= temp.size(); i++)
                cout << temp[i] << endl;


return 0;
}
user3527124
  • 63
  • 1
  • 2
  • 5
  • You need to split the string into tokens based on strings and numbers then do a lexicographic comparison one token at a time. – shuttle87 Oct 13 '14 at 23:26

1 Answers1

2

Assuming C++11, you can use a lambda and std::stoi to convert the valid parts of the strings to digits.

sort(temp.begin(), temp.end(), [] (const std::string& a, const std::string& b) { 
    std::string cmp_a { a.begin() + 4, a.end() };
    std::string cmp_b { b.begin() + 4, b.end() };
    return std::stoi(cmp_a) < std::stoi(cmp_b);
});

Of course, std::stoi will throw if the conversion fails, so ensure that the strings you're passing to it only contain digits.


In C++03, you can use Boost.Lexical_Cast:

int convert(const std::string& s, std::size_t pos)
{
    return boost::lexical_cast<int>(s.data() + pos, 
        std::distance(s.begin() + pos, s.end()));
}

bool predicate(const std::string& a, const std::string& b)
{
    return convert(a, 4) < convert(b, 4);
}

As noted in a comment, 4 is the hard-coded position where the first digit occurs. If it varies, you can use find_first_of:

const std::string numbers = "0123456789";

bool predicate(const std::string& a, const std::string& b)
{
    std::size_t a_start = a.find_first_of(numbers);
    std::size_t b_start = b.find_first_of(numbers);
    return convert(a, a_start) < convert(b, b_start);
}

A much better answer has already been written by Charles Salvia (that doesn't rely on Boost or C++11). He links to a page that implements natural sorting order as mentioned by another comment.

Community
  • 1
  • 1
  • thanks remyabel. Can you please describe why did you use + 4 here: std::string cmp_a { a.begin() + 4, a.end() }; – user3527124 Oct 13 '14 at 23:40
  • @user3527124 4 characters in "name". If this could vary you will need to search for the first numeric character. – Neil Kirk Oct 13 '14 at 23:40
  • I think I answered my own question..? Is this because name0, name20 etc.? a.begin + 4 will point to first numerical value after string "name". correct..? – user3527124 Oct 13 '14 at 23:42