If I have the string "2.5 4.2 6.9 1.1", how can I convert that into a vector of doubles as efficiently as possible?
            Asked
            
        
        
            Active
            
        
            Viewed 219 times
        
    3 Answers
4
            
            
        vector<double> convert_string_to_vec(std::string const & str)
{
    std::istringstream input{str};
    vector<double> output{std::istream_iterator<double>{input},
                          std::istream_iterator<double>{}};
    return output;
}
You'll need to include <sstream> as well as <iterator> for this to work. Here's a working example.
        AliciaBytes
        
- 7,300
 - 6
 - 36
 - 47
 
- 
                    2You need to either use universal initialization, `{}`, or stuff one of those iterators (ideally the first) in a nested set of parens, or you code will hit an [MVP](http://en.wikipedia.org/wiki/Most_vexing_parse). And minor: your decl is missing a semi-colon. – WhozCraig Nov 13 '13 at 00:48
 - 
                    Got to hate that mvp... Changed them all to universal initialization and added link to coliru example. thanks craig =) – AliciaBytes Nov 13 '13 at 00:54
 - 
                    Be happy we have UI now. Before with all the parens I kept having Lisp flashbacks from college. – WhozCraig Nov 13 '13 at 00:55
 - 
                    1You can always use named iterators, which you can declare in the same statement, avoiding mvp *and* saving you from having to tediously type `std::istream_iterator
` twice. http://coliru.stacked-crooked.com/a/dca982f0429e3595 – Benjamin Lindley Nov 13 '13 at 01:18 - 
                    This creates a vector and then returns a copy of that vector, so it could be made more efficient. – snips-n-snails Nov 13 '13 at 01:22
 - 
                    1@traal: In a world with [RVO](http://en.wikipedia.org/wiki/Return_value_optimization) and [move semantics](http://en.wikipedia.org/wiki/Move_semantics#Rvalue_references_and_move_constructors), no, it really can't. At least, not in that respect. There may be optimization opportunities in the string-to-double conversion though. – Benjamin Lindley Nov 13 '13 at 01:24
 - 
                    @traal like Benjamin said already, there shouldn't be a copy at all. And moving is insignificant compared to the `stringstream` performance. – AliciaBytes Nov 13 '13 at 01:32
 
0
            
            
        This is how I would generally do it. Possibly not the most efficient way, but very simple.
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
int main()
{
    std::string d("2.5 4.2 6.9 1.1");
    std::stringstream s(d);
    std::vector<double> result;
    double temp;
    while(s >> temp)
    {
        result.push_back(temp);
    }
    for(size_t i = 0; i < result.size(); ++i)
    {
        std::cout << result[i] << "\n";
    }
    return 0;
}
        Retired Ninja
        
- 4,785
 - 3
 - 25
 - 35
 
- 
                    is there a specific reason for not using `std::endl` but rather using `"\n"` ? – Varaquilex Nov 13 '13 at 00:52
 - 
                    1@Volkanİlbeyli `std::endl` flushes the stream as well as inserting a new line. There's no need to flush after each iteration so `'\n'` is preferred in this case. – David G Nov 13 '13 at 00:53
 - 
                    Yeah, the `"\n"` is to avoid extra flushing of the stream. Admittedly not all that important in a small example like this, but I'm trying to teach myself to prefer it for when there is a difference. – Retired Ninja Nov 13 '13 at 00:58
 
0
            
            
        Here's a unique way:
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
template <class Facet>
struct erasable_facet : Facet
{
    erasable_facet() : Facet(0) { }
    ~erasable_facet() { }
};
std::vector<double> convert(const std::string& str)
{
    using num_get = std::num_get<char>;
    erasable_facet<num_get> facet;
    std::stringbuf buf(str);
    std::vector<double> v;
    std::ios ios(nullptr);
    std::ios_base::iostate err = std::ios_base::goodbit;
    double d;
    std::istreambuf_iterator<char> it, end;
    do
    {
        it = facet.get(&buf, end, ios, err, d);
        buf.sbumpc(); // skip space
        if (!(err & std::ios_base::failbit) &&
            !(err & std::ios_base::badbit))
            v.push_back(d);
        else
            return v;
    } while (it != end);
    return v;
}
int main()
{
    std::string str = "1.24 5.32 9.53";
    auto v = convert(str);
}
        David G
        
- 94,763
 - 41
 - 167
 - 253