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;
}
1
  • 1
    You need to split the string into tokens based on strings and numbers then do a lexicographic comparison one token at a time. Commented Oct 13, 2014 at 23:26

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

3 Comments

thanks remyabel. Can you please describe why did you use + 4 here: std::string cmp_a { a.begin() + 4, a.end() };
@user3527124 4 characters in "name". If this could vary you will need to search for the first numeric character.
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..?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.