如何从一个std :: vector的构造的std :: string ?(How to co

2019-07-21 09:05发布

我想建立一个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?