Wil*_*mKF 24 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();
}
Run Code Online (Sandbox Code Playgroud)
我怎么可能这样做?
Okt*_*ist 60
std::string s;
for (std::vector<std::string>::const_iterator i = v.begin(); i != v.end(); ++i)
s += *i;
return s;
Run Code Online (Sandbox Code Playgroud)
std::string s;
std::for_each(v.begin(), v.end(), [&](const std::string &piece){ s += piece; });
return s;
Run Code Online (Sandbox Code Playgroud)
std::string s;
for (const auto &piece : v) s += piece;
return s;
Run Code Online (Sandbox Code Playgroud)
不要std::accumulate
用于字符串连接,它是经典的Schlemiel the Painter的算法,甚至比strcat
在C中使用的通常示例更糟糕.在没有C++ 11移动语义的情况下,它会为向量的每个元素产生两个不必要的累加器副本.即使使用移动语义,它仍然会为每个元素生成一个不必要的累加器副本.
以上三个例子是O(n).
std::accumulate
字符串是O(n²).
您可以
std::accumulate
通过提供自定义仿函数为字符串生成O(n):Run Code Online (Sandbox Code Playgroud)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)
),而body必须使用+=
not+
.
在当前预期成为C++ 20的草案中,定义std::accumulate
已被改变为std::move
在附加到累加器时使用,因此从C++ 20开始,对于字符串accumulate
将是O(n),并且可以使用作为单线:
std::string s = std::accumulate(v.begin(), v.end(), std::string{});
Run Code Online (Sandbox Code Playgroud)
And*_*owl 35
您可以使用std::accumulate()
标<numeric>
头中的标准函数(它的工作原理是因为operator +
为string
s 定义了重载,它返回了两个参数的串联):
#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!"
}
Run Code Online (Sandbox Code Playgroud)
或者,您可以使用更高效,更小的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!"
}
Run Code Online (Sandbox Code Playgroud)
为什么不使用operator +将它们添加到一起?
std::string string_from_vector(const std::vector<std::string> &pieces) {
return std::accumulate(pieces.begin(), pieces.end(), std::string(""));
}
Run Code Online (Sandbox Code Playgroud)
默认情况下,std :: accumulate使用std :: plus,并且在C++中添加两个字符串是连接,因为运算符+为std :: string重载.
我个人的选择是基于范围的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;
}
Run Code Online (Sandbox Code Playgroud)
这打印:
第一秒
在任何情况下,我发现该std::accumulate()
方法滥用该算法(无论复杂性问题如何).
Google Abseil 具有absl::StrJoin 函数可以满足您的需要。
来自他们的头文件的示例。请注意,分隔符也可以是""
// std::vector<std::string> v = {"foo", "bar", "baz"};
// std::string s = absl::StrJoin(v, "-");
// EXPECT_EQ("foo-bar-baz", s);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
43363 次 |
最近记录: |