How to implode a vector of strings into a string (the elegant way)

橙三吉。 提交于 2019-11-26 17:32:56
Andre Holzner

Use boost::algorithm::join(..):

#include <boost/algorithm/string/join.hpp>
...
std::string joinedString = boost::algorithm::join(elems, delim);

See also this question.

sehe
std::vector<std::string> strings;

const char* const delim = ", ";

std::ostringstream imploded;
std::copy(strings.begin(), strings.end(),
           std::ostream_iterator<std::string>(imploded, delim));

(include <string>, <vector>, <sstream> and <iterator>)

If you want to have a clean end (no trailing delimiter) have a look here

You should use std::ostringstream rather than std::string to build the output (then you can call its str() method at the end to get a string, so your interface need not change, only the temporary s).

From there, you could change to using std::ostream_iterator, like so:

copy(elems.begin(), elems.end(), ostream_iterator<string>(s, delim)); 

But this has two problems:

  1. delim now needs to be a const char*, rather than a single char. No big deal.
  2. std::ostream_iterator writes the delimiter after every single element, including the last. So you'd either need to erase the last one at the end, or write your own version of the iterator which doesn't have this annoyance. It'd be worth doing the latter if you have a lot of code that needs things like this; otherwise the whole mess might be best avoided (i.e. use ostringstream but not ostream_iterator).
Guss

Because I love one-liners (they are very useful for all kinds of weird stuff, as you'll see at the end), here's a solution using std::accumulate and C++11 lambda:

std::accumulate(alist.begin(), alist.end(), std::string(), 
    [](const std::string& a, const std::string& b) -> std::string { 
        return a + (a.length() > 0 ? "," : "") + b; 
    } )

I find this syntax useful with stream operator, where I don't want to have all kinds of weird logic out of scope from the stream operation, just to do a simple string join. Consider for example this return statement from method that formats a string using stream operators (using std;):

return (dynamic_cast<ostringstream&>(ostringstream()
    << "List content: " << endl
    << std::accumulate(alist.begin(), alist.end(), std::string(), 
        [](const std::string& a, const std::string& b) -> std::string { 
            return a + (a.length() > 0 ? "," : "") + b; 
        } ) << endl
    << "Maybe some more stuff" << endl
    )).str();
BlackMamba
string join(const vector<string>& vec, const char* delim)
{
    stringstream res;
    copy(vec.begin(), vec.end(), ostream_iterator<string>(res, delim));
    return res.str();
}

A version that uses std::accumulate:

#include <numeric>
#include <iostream>
#include <string>

struct infix {
  std::string sep;
  infix(const std::string& sep) : sep(sep) {}
  std::string operator()(const std::string& lhs, const std::string& rhs) {
    std::string rz(lhs);
    if(!lhs.empty() && !rhs.empty())
      rz += sep;
    rz += rhs;
    return rz;
  }
};

int main() {
  std::string a[] = { "Hello", "World", "is", "a", "program" };
  std::string sum = std::accumulate(a, a+5, std::string(), infix(", "));
  std::cout << sum << "\n";
}
Darien Pardinas

Here is another one that doesn't add the delimiter after the last element:

std::string concat_strings(const std::vector<std::string> &elements,
                           const std::string &separator)
{       
    if (!elements.empty())
    {
        std::stringstream ss;
        auto it = elements.cbegin();
        while (true)
        {
            ss << *it++;
            if (it != elements.cend())
                ss << separator;
            else
                return ss.str();
        }       
    }
    return "";
xtofl

Especially with bigger collections, you want to avoid having to check if youre still adding the first element or not to ensure no trailing separator...

So for the empty or single-element list, there is no iteration at all.

Empty ranges are trivial: return "".

Single element or multi-element can be handled perfectly by accumulate:

auto join = [](const auto &&range, const auto separator) {
    if (range.empty()) return std::string();

    return std::accumulate(
         next(begin(range)), // there is at least 1 element, so OK.
         end(range),

         range[0], // the initial value

         [&separator](auto result, const auto &value) {
             return result + separator + value;
         });
};

Running sample (require C++14): http://cpp.sh/8uspd

what about simple stupid solution?

std::string String::join(const std::vector<std::string> &lst, const std::string &delim)
{
    std::string ret;
    for(const auto &s : lst) {
        if(!ret.empty())
            ret += delim;
        ret += s;
    }
    return ret;
}

Using part of this answer to another question gives you a joined this, based on a separator without a trailing comma,

Usage:

std::vector<std::string> input_str = std::vector<std::string>({"a", "b", "c"});
std::string result = string_join(input_str, ",");
printf("%s", result.c_str());
/// a,b,c

Code:

std::string string_join(const std::vector<std::string>& elements, const char* const separator)
{
    switch (elements.size())
    {
        case 0:
            return "";
        case 1:
            return elements[0];
        default:
            std::ostringstream os;
            std::copy(elements.begin(), elements.end() - 1, std::ostream_iterator<std::string>(os, separator));
            os << *elements.rbegin();
            return os.str();
    }
}

Slightly long solution, but doesn't use std::ostringstream, and doesn't require a hack to remove the last delimiter.

http://www.ideone.com/hW1M9

And the code:

struct appender
{
  appender(char d, std::string& sd, int ic) : delim(d), dest(sd), count(ic)
  {
    dest.reserve(2048);
  }

  void operator()(std::string const& copy)
  {
    dest.append(copy);
    if (--count)
      dest.append(1, delim);
  }

  char delim;
  mutable std::string& dest;
  mutable int count;
};

void implode(const std::vector<std::string>& elems, char delim, std::string& s)
{
  std::for_each(elems.begin(), elems.end(), appender(delim, s, elems.size()));
}

just add !! String s = "";

for (int i = 0; i < doc.size(); i++)   //doc is the vector
    s += doc[i];

Here's what I use, simple and flexible

string joinList(vector<string> arr, string delimiter)
{
    if (arr.empty()) return "";

    string str;
    for (auto i : arr)
        str += i + delimiter;
    str = str.substr(0, str.size() - delimiter.size());
    return str;
}

using:

string a = joinList({ "a", "bbb", "c" }, "!@#");

output:

a!@#bbb!@#c

Firstly, a stream class ostringstream is needed here to do concatenation for many times and save the underlying trouble of excessive memory allocation.

Code:

string join(const vector<string>& vec, const char* delim)
{
    ostringstream oss;
    if(!string_vector.empty()) {
        copy(string_vector.begin(),string_vector.end() - 1, ostream_iterator<string>(oss, delim.c_str()));
    }
    return oss.str();
}

vector<string> string_vector {"1", "2"};
string delim("->");
string joined_string = join();  // get "1->2"

Explanation:

when thinking, treat oss here as std::cout

when we want to write:

std::cout << string_vector[0] << "->" << string_vector[1] << "->",

we can use the following STL classes as help:

ostream_iterator returns an wrapped output stream with delimiters automatically appended each time you use <<.

for instance,

ostream my_cout = ostream_iterator<string>(std::cout, "->")

wraps std:cout as my_cout

so each time you my_cout << "string_vector[0]",

it means std::cout << "string_vector[0]" << "->"

As for copy(vector.begin(), vector.end(), std::out);

it means std::cout << vector[0] << vector[1] (...) << vector[end]

try this, but using vector instead of list

template <class T>
std::string listToString(std::list<T> l){
    std::stringstream ss;
    for(std::list<int>::iterator it = l.begin(); it!=l.end(); ++it){
        ss << *it;
        if(std::distance(it,l.end())>1)
            ss << ", ";
    }
    return "[" + ss.str()+ "]";
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!