如何从std :: vector <string>?</string>构造一个std :: string

时间:2013-03-11 19:39:48

标签: c++ stl string-concatenation stringstream stdstring

我想从std::string建立一个std::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();
}

我还能怎么做?

8 个答案:

答案 0 :(得分:47)

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's algorithm,甚至比在C中使用strcat的常见示例更糟糕。 ++ 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必须是对非const的引用,即lambda返回类型   必须是一个参考(因此decltype(auto)),身体必须使用   +=不是+

C ++ 20

在预期成为C ++ 20的当前草案中,std::accumulate的定义在附加到累加器时altered使用std::move,所以从C + +20以后,accumulate对于字符串将 O(n),并且可以用作单行代码:

std::string s = std::accumulate(v.begin(), v.end(), std::string{});

答案 1 :(得分:35)

您可以使用<numeric>标头中的std::accumulate()标准函数(它可以正常工作,因为为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!"
}

答案 2 :(得分:8)

为什么不使用operator +将它们一起添加?

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重载了operator +。

答案 3 :(得分:6)

我个人的选择是基于范围的for循环,如Oktalist's answer

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;
}

打印:

  

第一,第二

无论如何,我发现std::accumulate()方法滥用了该算法(无论复杂性问题如何)。

答案 4 :(得分:2)

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

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"})

答案 5 :(得分:2)

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

来自header文件的示例。 请注意,分隔符也可以是""

//   std::vector<std::string> v = {"foo", "bar", "baz"};
//   std::string s = absl::StrJoin(v, "-");
//   EXPECT_EQ("foo-bar-baz", s);

答案 6 :(得分:0)

使用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();
}

答案 7 :(得分:0)

如果不需要尾随空格,请将accumulate中定义的<numeric>与自定义连接lambda一起使用。

#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