web-dev-qa-db-ja.com

std :: vector <string>からstd :: stringを作成する方法は?

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();
}

他にどのようにこれを行うことができますか?

21
WilliamKF

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を使用しないでください、これは古典的な 画家のアルゴリズムのシュミエル であり、通常の使用例よりもさらに悪いCのstrcat。C++ 11移動セマンティクスがない場合、ベクトルの各要素に対してアキュムレーターの2つの不要なコピーが発生します。移動セマンティクスを使用しても、各要素ごとにアキュムレーターの不要なコピーが1つ発生します。

上記の3つの例は、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は非constへの参照である必要があり、ラムダの戻り値の型は参照である必要があり(したがってdecltype(auto))、本体は+=ではなく+を使用する必要があります。

C++ 20

C++ 20になる予定の現在のドラフトでは、アキュムレータに追加するときにstd::accumulateを使用するためにstd::moveの定義が altered になっているため、C++ 20以降ではaccumulateは、文字列ではO(n)になり、ワンライナーとして使用できます。

std::string s = std::accumulate(v.begin(), v.end(), std::string{});
55
Oktalist

_<numeric>_ヘッダーから std::accumulate() 標準関数を使用できます(stringsに対して_operator +_のオーバーロードが定義されているため機能します) 2つの引数の連結を返します):

_#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!"
}
_
35
Andy Prowl

演算子+を使用してそれらを一緒に追加しないのはなぜですか?

std::string string_from_vector(const std::vector<std::string> &pieces) {
   return std::accumulate(pieces.begin(), pieces.end(), std::string(""));
}

std :: accumulateは、デフォルトでフードの下にstd :: plusを使用します。C++では、std :: stringに対して演算子+がオーバーロードされるため、2つの文字列を追加することは連結です。

8
bstamour

私の個人的な選択は、 Oktalist's answer のように、範囲ベースのforループです。

BoostはNiceソリューションも提供します:

_#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()アプローチは、そのアルゴリズムの誤用に近づいています(複雑さの問題に関係なく)。

6
Ali

パーティーに少し遅れましたが、初期化リストを使用できるという事実が気に入りました。

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"})
2
Benjamin K.

Google Abseilには、必要なことを行うabsl :: StrJoin関数があります。

header ファイルの例。セパレータは""

//   std::vector<std::string> v = {"foo", "bar", "baz"};
//   std::string s = absl::StrJoin(v, "-");
//   EXPECT_EQ("foo-bar-baz", s);
2
NoSenseEtAl

末尾のスペースが必要ない場合は、<numeric>で定義されているaccumulateをカスタム結合ラムダとともに使用します。

#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;
}

出力:

fee fi foe fum
1
user9494810

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();
}
1
PSIAlt