shblsh
shblsh

Reputation: 81

std::sort fails to sort elements of a std::vector<std::string>

I have the following code:

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <boost/foreach.hpp>
#include <boost/tokenizer.hpp>
#include <fstream>
#include <streambuf>

bool cmp(const std::string& lhs, const std::string& rhs) {
    return lhs < rhs;
}

int main(int argc, char **argv){
    /* USAGE: PROGRAM FILENAME DELIMITER */
    if (argc != 3){
        fprintf(stderr, "./program filename delimiter \n");
        exit(EXIT_FAILURE);
    }

    char *filename = argv[1];
    char *delimiter = argv[2];

    std::vector<std::string> vWords;
    std::vector<std::string> vWords_TMP;
    std::ifstream t(filename);
    std::string str((std::istreambuf_iterator<char>(t)),
                    std::istreambuf_iterator<char>());
    boost::char_separator<char> sep(delimiter);
    boost::tokenizer< boost::char_separator<char> > tokens(str, sep);
    BOOST_FOREACH (const std::string& t, tokens) {
        vWords.push_back(t);
    }
    vWords_TMP = vWords;
    for( std::vector<std::string>::const_iterator i = vWords.begin(); i != vWords.end(); ++i) std::cout << *i << '\n';
    std::sort(vWords_TMP.begin(), vWords_TMP.end());
    for( std::vector<std::string>::const_iterator i = vWords_TMP.begin(); i != vWords_TMP.end(); ++i) std::cout << *i << '\n';
}

However, when I run it, std::sort fails to sort the vector. I input the following file:

> FILE
UUUUUUUUUUUUUUUUUUUUU
AAAAAAAAAAAAAAAAAAAAA
KKKKKKKKKKKKKKKKKKKKK
BBBBBBBBBBBBBBBBBBBBB
YYYYYYYYYYYYYYYYYYYYY

Which should become:

AAAAAAAAAAAAAAAAAAAAA
BBBBBBBBBBBBBBBBBBBBB
KKKKKKKKKKKKKKKKKKKKK
UUUUUUUUUUUUUUUUUUUUU
YYYYYYYYYYYYYYYYYYYYY

But unfortunately the output is identical after the sort. Any ideas?

Upvotes: 1

Views: 426

Answers (3)

Adam
Adam

Reputation: 17339

Modify your vWords construction with a print statement:

BOOST_FOREACH (const std::string& t, tokens) {
    vWords.push_back(t);
    std::cout << "pushing token: \"" << t << "\"" << std::endl;
}

And you'll notice that the entire file contents get pushed into your vector as a single string. Obviously sorting a single element won't change anything.

It's up to you to decide what should happen instead.

I'm assuming you mean that you want delimiter to be a newline. The only way I'm aware of to pass a newline to your program, as it stands, on the command line is like this:

$ ./a.out file  "
> "
pushing token: "UUUUUUUUUUUUUUUUUUUUU"
pushing token: "AAAAAAAAAAAAAAAAAAAAA"
pushing token: "KKKKKKKKKKKKKKKKKKKKK"
pushing token: "BBBBBBBBBBBBBBBBBBBBB"
pushing token: "YYYYYYYYYYYYYYYYYYYYY"
UUUUUUUUUUUUUUUUUUUUU
AAAAAAAAAAAAAAAAAAAAA
KKKKKKKKKKKKKKKKKKKKK
BBBBBBBBBBBBBBBBBBBBB
YYYYYYYYYYYYYYYYYYYYY
AAAAAAAAAAAAAAAAAAAAA
BBBBBBBBBBBBBBBBBBBBB
KKKKKKKKKKKKKKKKKKKKK
UUUUUUUUUUUUUUUUUUUUU
YYYYYYYYYYYYYYYYYYYYY

(and note that your program works as I think you want it to)

The way I pass a newline as the command-line argument is that I have an opening " then the enter key, then closing " and enter again to run the command.

Upvotes: 1

kfsone
kfsone

Reputation: 24249

The problem appears to be that you are reading all the lines of the file into one string. The actual sort algorithm itself works, as demonstrated here

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

int main() {
    typedef std::vector<std::string> Strings;
    Strings strings = { "world", "good bye", "hello", "aloha" };
    sort(strings.begin(), strings.end());
    for (Strings::iterator it = strings.begin(); it != strings.end(); ++it) cout << *it << "\n";
    return 0;
}

Upvotes: 0

Slava
Slava

Reputation: 44258

I do not see the way you could pass carriage return as delimiter into your program, so you pass something else. And you get all lines from the file with carriage returns as one string. Sorting one string does not change anything, so you see the same output. To see if that the case change output loop to this:

for( std::vector<std::string>::const_iterator i = vWords_TMP.begin(); i != vWords_TMP.end(); ++i) 
    std::cout << "\"" << *i << "\"\n";

And check how many double quotes you see on the output.

Upvotes: 0

Related Questions