C++ 如何从 std::vector<string> 构造 std::string?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15347123/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to construct a std::string from a std::vector<string>?
提问by WilliamKF
I'd like to build a std::string
from a std::vector<std::string>
.
我想std::string
从std::vector<std::string>
.
I could use std::stringsteam
, but imagine there is a shorter way:
我可以使用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();
}
How else might I do this?
我还能怎么做?
回答by Oktalist
C++03
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 (the MSVC 2010 subset)
C++11 (MSVC 2010 子集)
std::string s;
std::for_each(v.begin(), v.end(), [&](const std::string &piece){ s += piece; });
return s;
C++11
C++11
std::string s;
for (const auto &piece : v) s += piece;
return s;
Don't use std::accumulate
for string concatenation, it is a classic Schlemiel the Painter's algorithm, even worse than the usual example using strcat
in C. Without C++11 move semantics, it incurs two unnecessary copies of the accumulator for each element of the vector. Even with move semantics, it still incurs one unnecessary copy of the accumulator for each element.
不要std::accumulate
用于字符串连接,它是经典的Schlemiel 画家算法,甚至比strcat
C 中使用的通常示例还要糟糕。如果没有 C++11 移动语义,它会为向量的每个元素产生两个不必要的累加器副本。即使使用移动语义,它仍然会为每个元素产生一个不必要的累加器副本。
The three examples above are O(n).
上面的三个例子是O(n)。
std::accumulate
is O(n2)for strings.
std::accumulate
对于字符串是O(n2)。
You could make
std::accumulate
O(n) for strings by supplying a custom functor:std::string s = std::accumulate(v.begin(), v.end(), std::string{}, [](std::string &s, const std::string &piece) -> decltype(auto) { return s += piece; });
Note that
s
must be a reference to non-const, the lambda return type must be a reference (hencedecltype(auto)
), and the body must use+=
not+
.
您可以
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
In the current draft of what is expected to become C++20, the definition of std::accumulate
has been alteredto use std::move
when appending to the accumulator, so from C++20 onwards, accumulate
will be O(n)for strings, and can be used as a one-liner:
在预期成为 C++20 的当前草案中, 的定义std::accumulate
已更改为std::move
在附加到累加器时使用,因此从 C++20 开始,对于字符串accumulate
将是O(n),并且可以使用作为单线:
std::string s = std::accumulate(v.begin(), v.end(), std::string{});
回答by Andy Prowl
You could use the std::accumulate()
standard function from the <numeric>
header (it works because an overload of operator +
is defined for string
s which returns the concatenation of its two arguments):
您可以使用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!"
}
Alternatively, you could use a more efficient, small for
cycle:
或者,您可以使用更高效的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!"
}
回答by bstamour
Why not just use operator + to add them together?
为什么不直接使用运算符 + 将它们加在一起呢?
std::string string_from_vector(const std::vector<std::string> &pieces) {
return std::accumulate(pieces.begin(), pieces.end(), std::string(""));
}
std::accumulate uses std::plus under the hood by default, and adding two strings is concatenation in C++, as the operator + is overloaded for std::string.
std::accumulate 默认情况下使用 std::plus ,并且在 C++ 中添加两个字符串是连接,因为运算符 + 为 std::string 重载。
回答by Ali
My personal choice would be the range-based for loop, as in Oktalist's answer.
我个人的选择是基于范围的 for 循环,如Oktalist's answer。
Boost also offers a nice solution:
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;
}
This prints:
这打印:
first, second
第一秒
In any case, I find the std::accumulate()
approach a misuse of that algorithm (regardless the complexity issues).
无论如何,我发现该std::accumulate()
方法滥用了该算法(无论复杂性问题如何)。
回答by Benjamin K.
A little late to the party, but I liked the fact that we can use initializer lists:
聚会有点晚了,但我喜欢我们可以使用初始化列表的事实:
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;
}
Then you can simply invoke (Python style):
然后你可以简单地调用(Python 风格):
join({"Hello", "World", "1"})
回答by NoSenseEtAl
Google Abseil has function absl::StrJoin that does what you need.
Google Abseil 具有功能 absl::StrJoin 可以满足您的需求。
Example from their headerfile.
Notice that separator can be also ""
来自他们的头文件的示例。请注意,分隔符也可以""
// std::vector<std::string> v = {"foo", "bar", "baz"};
// std::string s = absl::StrJoin(v, "-");
// EXPECT_EQ("foo-bar-baz", s);
回答by user9494810
If requires no trailing spaces, use accumulate
defined in <numeric>
with custom join lambda.
如果不需要尾随空格,请使用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;
}
Output:
输出:
fee fi foe fum
回答by PSIAlt
With c++11 the stringstreamway is not too scary:
使用 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();
}