私はワンライナーが大好きなので(最後に表示されるように、あらゆる種類の奇妙なものに非常に役立ちます)、std :: accumulateとC ++ 11ラムダを使用したソリューションを次に示します。
std::accumulate(alist.begin(), alist.end(), std::string(),
[](const std::string& a, const std::string& b) -> std::string {
return a + (a.length() > 0 ? "," : "") + b;
} )
この構文は、単純な文字列結合を行うためだけに、ストリーム操作の範囲外にあらゆる種類の奇妙なロジックを含めたくないストリーム演算子で役立つことがわかりました。たとえば、ストリーム演算子を使用して(std;を使用して)文字列をフォーマットするメソッドからのこのreturnステートメントについて考えてみます。
return (dynamic_cast<ostringstream&>(ostringstream()
<< "List content: " << endl
<< std::accumulate(alist.begin(), alist.end(), std::string(),
[](const std::string& a, const std::string& b) -> std::string {
return a + (a.length() > 0 ? "," : "") + b;
} ) << endl
<< "Maybe some more stuff" << endl
)).str();
更新:
コメントで@plexandoが指摘しているように、上記のコードは、配列が空の文字列で始まる場合、「最初の実行」のチェックで以前の実行が欠落しているために追加の文字がないため、誤動作が発生します。すべての実行で「最初に実行された」チェックを実行するのは奇妙です(つまり、コードが最適化されていません)。
リストに少なくとも1つの要素があることがわかっていれば、これらの問題の両方の解決策は簡単です。OTOH、リストに少なくとも1つの要素がないことがわかっている場合は、実行をさらに短縮できます。
結果のコードはそれほどきれいではないと思うので、ここに正しい解決策として追加しますが、上記の説明にはまだメリットがあると思います。
alist.empty() ? "" :
++alist.begin(), alist.end(),
*alist.begin(),
[](auto& a, auto& b) { return a + "," + b; });
ノート:
- 最初の要素への直接アクセスをサポートするコンテナーの場合、代わりに3番目の引数にそれを使用する方がおそらく良いでしょう
alist[0]
。ベクトルの場合も同様です。
- コメントとチャットでの議論によると、ラムダはまだいくつかのコピーを行います。これは、代わりにこの(あまりきれいではない)ラムダを使用することで最小限に抑えることができます。
[](auto&& a, auto&& b) -> auto& { a += ','; a += b; return a; })
これは(GCC 10では)パフォーマンスをx10以上向上させます。提案してくれた@Deduplicatorに感謝します。私はまだここで何が起こっているのか理解しようとしています。