gkraft
gkraft

Reputation: 33

How to sort a vector of structs based on a vector<string> within the vector to be sorted?

What is the best way to alphabetically sort a vector of structures based on the first word in every vector of all the structures in the vector of structures?

struct sentence{
    vector<string> words;
};

vector<sentence> allSentences;

In other words, how to sort allSentences based on words[0]?


EDIT: I used the following solution:

bool cmp(const sentence& lhs, const sentence & rhs)
{
  return lhs.words[0] < rhs.words[0];
}

std::sort(allSentences.begin(), allSentences.end(), cmp);

Upvotes: 3

Views: 5044

Answers (3)

leemes
leemes

Reputation: 45675

Generally, there are three different types of scenarios for comparison implementations you should consider.

  1. A comparison of your object that makes always sense. It's independent from the scenario in which you want to compare objects. Then: Implement operator< for your class. This operator is used whenever two objects are compared (with <, which the standard algorithms do). (For single scenarios, you can still "overwrite" this behavior using the other methods below).

    For this, extend your class with the following function:

    struct sentence{
        vector<string> words;
        bool operator<(const sentence &other) const {
            return this->words[0] < other.words[0];
        }
    };
    

    Then, just call the standard sorting algorithm on your vector of sentences without other arguments:

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

    However, your scenario doesn't sound like this is the best method, since comparing by the first word is something you don't want to have always, maybe only in one case.

  2. A comparison of your object which will be used only once. In C++11, you have lambda functions (anonymous, literally inlined functions), which can be passed directly to the algorithm function in which it will be used, like std::sort in this scenario. This is my favorite solution:

    // Sort lexicographical by first word
    std::sort(allSentences.begin(), allSentences.end(),
              [](const sentence& a, const sentence& b) {
        a.words[0] < b.words[0];
    });
    

    In C++03, where you don't have lambdas, use to the 3rd solution:

  3. A set of different, re-usable comparison methods, maybe a parameterized comparison function. Examples are: Compare by the first word, compare by length, compare by something else... In this case, implement the comparison function(s) either as free-standing functions and use function pointers, or implement them as functors (which can be parameterized). Also, lambdas stored in variables do the job in this case.

    This method has the advantage to name the comparison methods, giving them a meaning. If you use different comparisons for the same object, but re-use them, this is a huge advantage:

    // Lexicographical comparison by the first word only
    bool compareLexByFirstWord(const sentence& a, const sentence& b) {
        return a.words[0] < b.words[0];
    }
    
    // Lexicographical comparison by all words
    bool compareLex(const sentence& a, const sentence& b) {
        return a.words < b.words;
    }
    
    // Decide which behavior to use when actually using the comparison:
    std::sort(sentence.begin(), sentence.end(), compareLexByFirstWord);
    std::sort(sentence.begin(), sentence.end(), compareLex);
    

Upvotes: 3

juanchopanza
juanchopanza

Reputation: 227418

Provide a suitable comparison binary function and pass it on to std::sort. For example

bool cmp(const sentence& lhs, const sentence & rhs)
{
  return lhs.words[0] < rhs.words[0];
}

then

std::sort(allSentences.begin(), allSentences.end(), cmp);

Alternatively, in C++11 you can use a lambda anonymous function

std::sort(allSentences.begin(), allSentences.end(), 
          [](const sentence& lhs, const sentence & rhs) {
                     return lhs.words[0] < rhs.words[0];}
         );

Upvotes: 6

Joseph Mansfield
Joseph Mansfield

Reputation: 110658

You need some comparison function that you can pass to std::sort:

bool compare(const sentence& a, const sentence& b)
{
  return a.words[0] < b.words[0];
}

As you can see, it takes two sentences and returns true if the first word of the first sentence is "less than" the first word of the second sentence.

Then you can sort allSentences very easily:

std::sort(allSentences.begin(), allSentences.end(), compare);

Of course, using this comparison means that sentences like {"hello", "world"} and {"hello", "friend"} will compare equal. But that's what you've asked for.

Upvotes: 3

Related Questions