0

I have the following string:

1 -2 -8 4 51

I would like to get a vector with 5 elements, each of them corresponding to the 5 numbers in the string. Basically, I'd like to split the above string by space as a delimiter.

I've found a lot of questions like this on Stack Overflow but so far any of them is able to get neither the first "1" nor the last one (from 51). My code is the following:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <sstream>

using namespace std;

std::vector<std::string> split(std::string str)
{
    std::string buf; 
    std::stringstream ss(str); 
    vector<std::string> tokens; 

    while (ss >> buf)
        tokens.push_back(buf);
    return tokens;
}

int main()
{

    std::string temps = "1 -2 -8 4 51";

    std::vector<std::string> x = split(temps);
    for (int j = 0; j < x.size(); j++){
        cout << x[j] << endl;    
    }
}

My output is the following:

-2
-8
4
5

As you can see, the first and the last 1 are skipped. I'm very new to C++ (I've been maybe too much used to the built-in functions .split() of other languages) but I can't see anything wrong on my above code. Can anyone please help me understanding what I'm doing wrong?

Matteo NNZ
  • 11,930
  • 12
  • 52
  • 89
  • 5
    err works fine here. I get `1 -2 -8 4 51` as expected... – Jean-François Fabre Nov 01 '16 at 18:28
  • 6
    [Cannot Reproduce](http://coliru.stacked-crooked.com/a/cffe001aedf4e0ee) – NathanOliver Nov 01 '16 at 18:29
  • What's your compiler? Works fine on gcc: http://melpon.org/wandbox/permlink/RZOT5kbvHvPraz5b – krzaq Nov 01 '16 at 18:29
  • Maybe this is a far catch but: print out a newline at the beginning of your program. Maybe you just oversee the first one. Another issue: You may get a different type back from x.size than int. Try to cast x.size() to int – Kev1n91 Nov 01 '16 at 18:35
  • I'm practicing on a [coding challenge website](https://www.codingame.com), but if you guys cannot reproduce I guess it's an issue of their compiler so I'm gonna close this thread. Sorry about that. – Matteo NNZ Nov 01 '16 at 18:35
  • Furthermore: the size() operator gives back the type [size_t] (http://stackoverflow.com/questions/2550774/what-is-size-t-in-c) which is unsigned, but j was initialized as a signed integer. Maybe that causes some trouble. I tried it with other online compilers and your code worked. – Kev1n91 Nov 01 '16 at 18:43

1 Answers1

1

The code you showed works fine in general. The output is as expected, so the problem has to be outside of the code you showed.

However, note that your vector will contain std::string values, not int values. Also, you should consider using std::istringstream for input instead of using std::stringstream.

If you want a vector of integers, try this instead:

#include <iostream>
#include <vector>
#include <string>
#include <sstream>

std::vector<int> split(const std::string &str)
{
    int num; 
    std::istringstream iss(str); 
    std::vector<int> tokens; 

    while (iss >> num)
        tokens.push_back(num);

    return tokens;
}

int main()
{
    std::string temps = "1 -2 -8 4 51";

    std::vector<int> x = split(temps);
    for (int j = 0; j < x.size(); j++) {
        std::cout << x[j] << std::endl;
    }

    return 0;
}

You could then make split() use std::istream_iterator and std::back_inserter instead of a manual loop, eg:

#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <iterator>
#include <algorithm>

std::vector<int> split(const std::string &str)
{
    std::istringstream iss(str); 
    std::vector<int> tokens; 

    std::copy(
        std::istream_iterator<int>(iss),
        std::istream_iterator<int>(),
        std::back_inserter(tokens)
    );

    return tokens;
}

int main()
{
    std::string temps = "1 -2 -8 4 51";

    std::vector<int> x = split(temps);
    for (int j = 0; j < x.size(); j++) {
        std::cout << x[j] << std::endl;
    }

    return 0;
}

And then you could make `split() be a template function so it can return a vector of different types depending on what you want from the input string, eg:

#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <iterator>
#include <algorithm>

template<typename T>
std::vector<T> split(const std::string &str)
{
    std::istringstream iss(str); 
    std::vector<T> tokens; 

    std::copy(
        std::istream_iterator<T>(iss),
        std::istream_iterator<T>(),
        std::back_inserter(tokens)
    );

    return tokens;
}

int main()
{
    std::string temps = "1 -2 -8 4 51";

    std::vector<int> x = split<int>(temps);
    for (int j = 0; j < x.size(); j++) {
        std::cout << x[j] << std::endl;
    }

    return 0;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770