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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 19:18:12  来源:igfitidea点击:

How to construct a std::string from a std::vector<string>?

c++stlstring-concatenationstringstreamstdstring

提问by WilliamKF

I'd like to build a std::stringfrom a std::vector<std::string>.

我想std::stringstd::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::accumulatefor string concatenation, it is a classic Schlemiel the Painter's algorithm, even worse than the usual example using strcatin 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 画家算法,甚至比strcatC 中使用的通常示例还要糟糕。如果没有 C++11 移动语义,它会为向量的每个元素产生两个不必要的累加器副本。即使使用移动语义,它仍然会为每个元素产生一个不必要的累加器副本。

The three examples above are O(n).

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

std::accumulateis O(n2)for strings.

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

You could make std::accumulateO(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 smust be a reference to non-const, the lambda return type must be a reference (hence decltype(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::accumulatehas been alteredto use std::movewhen appending to the accumulator, so from C++20 onwards, accumulatewill 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 strings which returns the concatenation of its two arguments):

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

#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 forcycle:

或者,您可以使用更高效的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 accumulatedefined 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();
}