84

I have a vector<data> info where data is defined as:

struct data{
    string word;
    int number;
};

I need to sort info by the length of the word strings. Is there a quick and simple way to do it?

greatwolf
  • 20,287
  • 13
  • 71
  • 105
calccrypto
  • 8,583
  • 21
  • 68
  • 99

4 Answers4

114

Use a comparison function:

bool compareByLength(const data &a, const data &b)
{
    return a.word.size() < b.word.size();
}

and then use std::sort in the header #include <algorithm>:

std::sort(info.begin(), info.end(), compareByLength);
TryToSolveItSimple
  • 873
  • 1
  • 12
  • 23
Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • 2
    What if I wish to sort the vector in a lexicographic manner according to the string filed ? (I'm using C++11 if it matters). Is there a way to approach it other than defining a comparison function /use lambda and instead use the integral operator< of std::string ? Below is my solution using lambda: sort(info.begin(),info.end(), [](const data& d1, const data& d2) { return (d1.word.compare(d2.word) < 0); }); – Guy Avraham Jul 06 '17 at 06:31
48

Just make a comparison function/functor:

bool my_cmp(const data& a, const data& b)
{
    // smallest comes first
    return a.word.size() < b.word.size();
}

std::sort(info.begin(), info.end(), my_cmp);

Or provide an bool operator<(const data& a) const in your data class:

struct data {
    string word;
    int number;

    bool operator<(const data& a) const
    {
        return word.size() < a.word.size();
    }
};

or non-member as Fred said:

struct data {
    string word;
    int number;
};

bool operator<(const data& a, const data& b)
{
    return a.word.size() < b.word.size();
}

and just call std::sort():

std::sort(info.begin(), info.end());
Murilo Vasconcelos
  • 4,677
  • 24
  • 27
5

Yes: you can sort using a custom comparison function:

std::sort(info.begin(), info.end(), my_custom_comparison);

my_custom_comparison needs to be a function or a class with an operator() overload (a functor) that takes two data objects and returns a bool indicating whether the first is ordered prior to the second (i.e., first < second). Alternatively, you can overload operator< for your class type data; operator< is the default ordering used by std::sort.

Either way, the comparison function must yield a strict weak ordering of the elements.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
4

As others have mentioned, you could use a comparison function, but you can also overload the < operator and the default less<T> functor will work as well:

struct data {
    string word;
    int number;
    bool operator < (const data& rhs) const {
        return word.size() < rhs.word.size();
    }
};

Then it's just:

std::sort(info.begin(), info.end());

Edit

As James McNellis pointed out, sort does not actually use the less<T> functor by default. However, the rest of the statement that the less<T> functor will work as well is still correct, which means that if you wanted to put struct datas into a std::map or std::set this would still work, but the other answers which provide a comparison function would need additional code to work with either.

user470379
  • 4,879
  • 16
  • 21
  • Interestingly, while `std::map` and `std::set` default to using `std::less`, `std::sort` and the rest of the sorting functions default to using `operator<`. You'll only notice a difference if you specialize `std::less` to do something other than what `operator<` does. – James McNellis Feb 03 '11 at 23:00
  • When I said "you'll only notice a difference if...," I was wrong. You'll also notice a difference if you have a container of pointers, e.g. `std::vector v; v.insert(new int); v.insert(new int); std::sort(v.begin(), v.end());`, since the behavior is undefined if you compare unrelated pointers using `<`. That said, why you'd want to sort a container of pointers by the pointer value and not the value of the pointed-to object, I don't know. – James McNellis Feb 03 '11 at 23:57