我想建立一个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();
}
我还能有别的可能做到这一点?
Answer 1:
你可以使用std::accumulate()
标准函数从<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!"
}
Answer 2:
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
字符串连接 ,这是一个经典的倒楣的画家算法 ,比使用通常的例子更糟糕strcat
在C.如果没有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
必须是非常量的基准,拉姆达返回类型必须是一个参考(因此decltype(auto)
),和所述主体必须使用+=
未+
。
C ++ 20
在什么是有望成为C ++ 20当前草案中,定义std::accumulate
已改变使用std::move
追加到蓄电池时,所以从C ++ 20日起, accumulate
将是O( n)的字符串,和可以用作一个班轮:
std::string s = std::accumulate(v.begin(), v.end(), std::string{});
Answer 3:
为什么不直接使用运营商+,将其添加在一起吗?
std::string string_from_vector(const std::vector<std::string> &pieces) {
return std::accumulate(pieces.begin(), pieces.end(), std::string(""));
}
的std ::累积使用的std ::加默认罩,并加入两个字符串下是级联在C ++中,当操作者+过载对的std :: string。
Answer 4:
我个人的选择将是循环的基础范围,如Oktalist的答案 。
升压还提供了一个很好的解决方案:
#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()
接近该算法(不考虑复杂性问题)的滥用。
Answer 5:
有点迟到了,但我喜欢的事实,我们可以使用初始化列表:
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"})
Answer 6:
谷歌绕绳下降具有功能ABSL :: StrJoin已经做了你所需要的。
从它们的例子头文件。 请注意,隔膜还可以""
// std::vector<std::string> v = {"foo", "bar", "baz"};
// std::string s = absl::StrJoin(v, "-");
// EXPECT_EQ("foo-bar-baz", s);
Answer 7:
用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();
}
文章来源: How to construct a std::string from a std::vector?