Convert vector<int> to delimited string
Asked Answered
T

2

12

As I see here there is a fast and short way to Convert vector to string separated with a character in c#:

var result = string.Join(";", data); 
var result = string.Join(";", data.Select(x => x.ToString()).ToArray()); 

I wan to know is there a same way in c++ to do this?

Twayblade answered 28/12, 2013 at 17:28 Comment(1)
No, there isn't with std::string, if you meant that!Tyson
K
23
#include <sstream>
#include <string>
#include <vector>
#include <iterator>
#include <iostream>

int main()
{
    std::vector<int> data = {42, 1, 2, 3, 4, 5};

    std::ostringstream oss;
    std::copy(data.begin(), data.end(), std::ostream_iterator<int>(oss, ";"));

    std::string result( oss.str() );
    std::cout << result << "\n";
}

N.B. In C++11, you can use the more general form

using std::begin;
using std::end;
std::copy(begin(data), end(data), std::ostream_iterator<int>(oss, ";"));

Where the using-declarations are not required if ADL can be used (like in the example above).


Also possible, but maybe a bit less efficient:

std::string s;
for(auto const& e : v) s += std::to_string(e) + ";";

which can be written via std::accumulate in <algorithm> as:

std::string s = std::accumulate(begin(v), end(v), std::string{},
    [](std::string r, int p){ return std::move(r) + std::to_string(p) + ";"; });

(IIRC there was some method to eliminate the copying, maybe by taking the lambda-parameter by reference std::string& r.)


A version w/o the trailing semi-colon (thanks to Dietmar Kühl):

std::vector<int> data = {42, 1, 2, 3, 4, 5};

std::ostringstream out;
if (!v.empty())
{
    std::copy(v.begin(), v.end() - 1, std::ostream_iterator<int>(out, ";"));
    out << v.back();
}

std::string result( out.str() );
std::cout << result << "\n";
Kif answered 28/12, 2013 at 17:32 Comment(11)
@Robᵩ I missed the #include <string> ;)Kif
+1 It might help the pedagogy if you named your input and result variables similarly to OP's: std::vector<int> data and std::string result.Sowers
Sadly, there is trailing semicolon where there probably shouldn't be one.Petal
@DietmarKühl Yes, but I couldn't come up with a similarly simple solution to get rid of it.Kif
I was thinking something like std::string s = v.empty()? std::string{""}: std::accumulate(v.begin() + 1, v.end(), v.front(), [](std::string const& s, int i) { return s + ";" + std::to_string(i); });Petal
@DietmarKühl That's quite nice. There's some additional copying like in my accumulate example (from the intermediary result to the s + ";"). Maybe, as I mentioned, taking by ref + moving could help.Kif
... or, of course, std::ostringstream out; if (!v.empty()) { std::copy(v.begin(), v.end() - 1, std::ostream_iterator<int>(out, ";")); out << v.back(); }; std::string s = out.str();Petal
@DietmarKühl Should to_string be called unqualified?Kif
@Twayblade Use v.begin() and v.end(). I tend to use C++11's free functions begin and end via ADL; it's one character less to type ;)Kif
@DyP: seem it wouldn't have any reason to find std::to_string() when called with an int. You'd need using std::to_lower; before it.Petal
@DietmarKühl Yes, was meant as a more general question (similar to std::begin and std::swap).Kif
V
2

Expanding on the accepted answer a little, I took the code and made a generic template version that works not only with a vector of ints but works with any types that work with stringstream:

template <typename T>
std::string VectorToCSV(const std::vector<T>& vec)
{
    std::ostringstream out;
    if (!vec.empty())
    {
        std::copy(std::begin(vec), std::end(vec) - 1, std::ostream_iterator<T>(out, ";"));
        out << vec.back();
    }

    return out.str();
}

This works with Template Argument Deduction, so to call it like this:

// Vector of ints example
std::vector<int> vec_of_ints = { 1, 2, 3, 4};    
std::string ints_csv = VectorToCSV(vec_of_ints);

// Vector of strings example
std::vector<std::string> vec_of_strings = { "Hello", "World"};
std::string strings_csv = VectorToCSV(vec_of_strings);
Visigoth answered 16/3, 2022 at 11:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.