Convert a vector<int> to a string

Viewed 113680

I have a vector<int> container that has integers (e.g. {1,2,3,4}) and I would like to convert to a string of the form

"1,2,3,4"

What is the cleanest way to do that in C++? In Python this is how I would do it:

>>> array = [1,2,3,4]
>>> ",".join(map(str,array))
'1,2,3,4'
25 Answers
string s;
for (auto i : v)
    s += (s.empty() ? "" : ",") + to_string(i);

why answers here are so ridiculously complex

string vec2str( vector<int> v){
        string s="";
        for (auto e: v){
            s+=to_string(e);
            s+=',';
        }
        s.pop_back();
        return s;
   }

The following is a simple and practical way to convert elements in a vector to a string:

std::string join(const std::vector<int>& numbers, const std::string& delimiter = ",") {
    std::ostringstream result;
    for (const auto number : numbers) {
        if (result.tellp() > 0) { // not first round
            result << delimiter;
        }
        result << number;
    }
    return result.str();
}

You need to #include <sstream> for ostringstream.

Expanding on the attempt of @sbi at a generic solution that is not restricted to std::vector<int> or a specific return string type. The code presented below can be used like this:

std::vector<int> vec{ 1, 2, 3 };

// Call modern range-based overload.
auto str     = join( vec,  "," );
auto wideStr = join( vec, L"," );

// Call old-school iterator-based overload.
auto str     = join( vec.begin(), vec.end(),  "," );
auto wideStr = join( vec.begin(), vec.end(), L"," );

In the original code, template argument deduction does not work to produce the right return string type if the separator is a string literal (as in the samples above). In this case, the typedefs like Str::value_type in the function body are incorrect. The code assumes that Str is always a type like std::basic_string, so it obviously fails for string literals.

To fix this, the following code tries to deduce only the character type from the separator argument and uses that to produce a default return string type. This is achieved using boost::range_value, which extracts the element type from the given range type.

#include <string>
#include <sstream>
#include <boost/range.hpp>

template< class Sep, class Str = std::basic_string< typename boost::range_value< Sep >::type >, class InputIt >
Str join( InputIt first, const InputIt last, const Sep& sep )
{
    using char_type          = typename Str::value_type;
    using traits_type        = typename Str::traits_type;
    using allocator_type     = typename Str::allocator_type;
    using ostringstream_type = std::basic_ostringstream< char_type, traits_type, allocator_type >;

    ostringstream_type result;

    if( first != last )
    {
        result << *first++;
    }
    while( first != last ) 
    {
        result << sep << *first++;
    }
    return result.str();
}

Now we can easily provide a range-based overload that simply forwards to the iterator-based overload:

template <class Sep, class Str = std::basic_string< typename boost::range_value<Sep>::type >, class InputRange>
Str join( const InputRange &input, const Sep &sep )
{
    // Include the standard begin() and end() in the overload set for ADL. This makes the 
    // function work for standard types (including arrays), aswell as any custom types 
    // that have begin() and end() member functions or overloads of the standalone functions.
    using std::begin; using std::end;

    // Call iterator-based overload.
    return join( begin(input), end(input), sep );
}

Live Demo at Coliru

Here is an easy way to convert a vector of integers to strings.

#include <bits/stdc++.h>
using namespace std;
int main()
{
    vector<int> A = {1, 2, 3, 4};
    string s = "";
    for (int i = 0; i < A.size(); i++)
    {
        s = s + to_string(A[i]) + ",";
    }
    s = s.substr(0, s.length() - 1); //Remove last character
    cout << s;
}

join using template function

I used a template function to join the vector items, and removed the unnecessary if statement by iterating through only the first to penultimate items in the vector, then joining the last item after the for loop. This also obviates the need for extra code to remove the extra separator at the end of the joined string. So, no if statements slowing down the iteration and no superfluous separator that needs tidying up.

This produces an elegant function call to join a vector of string, integer, or double, etc.

I wrote two versions: one returns a string; the other writes directly to a stream.

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

// Return a string of joined vector items.
template<typename T>
string join(const vector<T>& v, const string& sep)
{
    ostringstream oss;
    const auto LAST = v.end() - 1;
    // Iterate through the first to penultimate items appending the separator.
    for (typename vector<T>::const_iterator p = v.begin(); p != LAST; ++p)
    {
        oss << *p << sep;
    }
    // Join the last item without a separator.
    oss << *LAST;
    return oss.str();
}

// Write joined vector items directly to a stream.
template<typename T>
void join(const vector<T>& v, const string& sep, ostream& os)
{
    const auto LAST = v.end() - 1;
    // Iterate through the first to penultimate items appending the separator.
    for (typename vector<T>::const_iterator p = v.begin(); p != LAST; ++p)
    {
        os << *p << sep;
    }
    // Join the last item without a separator.
    os << *LAST;
}

int main()
{
    vector<string> strings
    {
        "Joined",
        "from",
        "beginning",
        "to",
        "end"
    };
    vector<int> integers{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    vector<double> doubles{ 1.2, 3.4, 5.6, 7.8, 9.0 };

    cout << join(strings, "... ") << endl << endl;
    cout << join(integers, ", ") << endl << endl;
    cout << join(doubles, "; ") << endl << endl;

    join(strings, "... ", cout);
    cout << endl << endl;
    join(integers, ",  ", cout);
    cout << endl << endl;
    join(doubles, ";  ", cout);
    cout << endl << endl;

    return 0;
}

Output

Joined... from... beginning... to... end

1, 2, 3, 4, 5, 6, 7, 8, 9, 10

1.2; 3.4; 5.6; 7.8; 9

Joined... from... beginning... to... end

1, 2, 3, 4, 5, 6, 7, 8, 9, 10

1.2; 3.4; 5.6; 7.8; 9
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v{{1,2,3,4}};
    std::string str;

    // ----->
    if (! v.empty())
    {
        str = std::to_string(*v.begin());
        for (auto it = std::next(v.begin()); it != v.end(); ++it)
            str.append("," + std::to_string(*it));
    }
    // <-----
    
    std::cout << str << "\n";
}

Yet another way to solve this using std::accumulate from numeric library (#include <numeric>):

std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
auto comma_fold = [](std::string a, int b) { return std::move(a) + ',' + std::to_string(b); };
std::string s = std::accumulate(std::next(v.begin()), v.end(),
                                std::to_string(v[0]), // start with first element
                                comma_fold);
std::cout << s << std::endl; // 1,2,3,4,5,6,7,8,9,10

Simple solution/hack... not elegant but it works

const auto vecToString = [](std::vector<int> input_vector)
{
    std::string holder = "";

    for (auto s : input_vector){
        holder += std::to_string(s);
        if(input_vector.back() != s){
            holder += ", ";
        }
    }

    return holder;
};
Related