56

我想std::stringstd::vector<std::string>.

我可以使用std::stringsteam,但想象有一种更短的方法:

std::string string_from_vector(const std::vector<std::string> &pieces) {
  std::stringstream ss;

  for(std::vector<std::string>::const_iterator itr = pieces.begin();
      itr != pieces.end();
      ++itr) {
    ss << *itr;
  }

  return ss.str();
}

我还能怎么做?

4

8 回答 8

109

C++03

std::string s;
for (std::vector<std::string>::const_iterator i = v.begin(); i != v.end(); ++i)
    s += *i;
return s;

C++11 (MSVC 2010 子集)

std::string s;
std::for_each(v.begin(), v.end(), [&](const std::string &piece){ s += piece; });
return s;

C++11

std::string s;
for (const auto &piece : v) s += piece;
return s;

不要std::accumulate用于字符串连接,它是经典的 Schlemiel the Painter 算法,甚至比 C 中使用的通常示例更糟糕strcat。如果没有 C++11 移动语义,它会为向量的每个元素产生两个不必要的累加器副本。即使使用移动语义,它仍然会为每个元素产生一个不必要的累加器副本。

上面的三个例子是O(n)

std::accumulate对于字符串是O(n²)

您可以std::accumulate通过提供自定义函子为字符串制作 O(n):

std::string s = std::accumulate(v.begin(), v.end(), std::string{},
    [](std::string &s, const std::string &piece) -> decltype(auto) { return s += piece; });

请注意,s必须是对非常量的引用,lambda 返回类型必须是引用(因此decltype(auto)),并且主体必须使用 +=not +

C++20

在预计将成为 C++20 的当前草案中,std::accumulate更改std::move在附加到累加器时使用的定义,因此从 C++20 开始,字符串accumulate将是O(n),并且可以使用作为单线:

std::string s = std::accumulate(v.begin(), v.end(), std::string{});
于 2013-09-09T17:30:04.863 回答
38

您可以使用标头中的std::accumulate()标准函数(它之所以有效,是因为为 s 定义了<numeric>一个重载,它返回其两个参数的串联):operator +string

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

int main()
{
    std::vector<std::string> v{"Hello, ", " Cruel ", "World!"};
    std::string s;
    s = accumulate(begin(v), end(v), s);
    std::cout << s; // Will print "Hello, Cruel World!"
}

或者,您可以使用更高效、更小的for循环:

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

int main()
{
    std::vector<std::string> v{"Hello, ", "Cruel ", "World!"};
    std::string result;
    for (auto const& s : v) { result += s; }
    std::cout << result; // Will print "Hello, Cruel World!"
}
于 2013-03-11T19:43:11.620 回答
13

我个人的选择是基于范围的 for 循环,如Oktalist 的回答

Boost 还提供了一个不错的解决方案:

#include <boost/algorithm/string/join.hpp>
#include <iostream>
#include <vector>

int main() {

    std::vector<std::string> v{"first", "second"};

    std::string joined = boost::algorithm::join(v, ", ");

    std::cout << joined << std::endl;
}

这打印:

第一秒

于 2014-05-17T17:44:29.007 回答
8

为什么不直接使用运算符 + 将它们相加呢?

std::string string_from_vector(const std::vector<std::string> &pieces) {
   return std::accumulate(pieces.begin(), pieces.end(), std::string(""));
}

std::accumulate 默认在后台使用 std::plus,在 C++ 中添加两个字符串是连接,因为运算符 + 为 std::string 重载。

于 2013-03-11T19:43:59.350 回答
4

Google Abseil 具有功能 absl::StrJoin 可以满足您的需求。

他们的头文件中的示例。请注意,分隔符也可以是""

//   std::vector<std::string> v = {"foo", "bar", "baz"};
//   std::string s = absl::StrJoin(v, "-");
//   EXPECT_EQ("foo-bar-baz", s);
于 2017-12-13T03:04:37.390 回答
3

聚会有点晚了,但我喜欢我们可以使用初始化列表的事实:

std::string join(std::initializer_list<std::string> i)
{
  std::vector<std::string> v(i);
  std::string res;
  for (const auto &s: v) res += s;
  return res;   
}

然后你可以简单地调用(Python风格):

join({"Hello", "World", "1"})
于 2015-07-23T11:18:05.340 回答
1

使用 c++11 的stringstream方式并不太可怕:

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

int main()
{
    std::vector<std::string> v{"Hello, ", " Cruel ", "World!"};
   std::stringstream s;
   std::for_each(begin(v), end(v), [&s](const std::string &elem) { s << elem; } );
   std::cout << s.str();
}
于 2013-03-11T20:22:01.730 回答
1

如果不需要尾随空格,请使用自定义连接 lambdaaccumulate中的定义。<numeric>

#include <iostream>
#include <numeric>
#include <vector>

using namespace std;


int main() {
    vector<string> v;
    string s;

    v.push_back(string("fee"));
    v.push_back(string("fi"));
    v.push_back(string("foe"));
    v.push_back(string("fum"));

    s = accumulate(begin(v), end(v), string(),
                   [](string lhs, const string &rhs) { return lhs.empty() ? rhs : lhs + ' ' + rhs; }
    );
    cout << s << endl;
    return 0;
}

输出:

fee fi foe fum
于 2019-06-17T01:24:47.060 回答