结合一个字符串向量

28

我一直在阅读《C++加速学习》,我必须说这是一本有趣的书。

在第6章中,我需要使用来自<algorithm>的函数将vector<string>连接成一个字符串。我可以使用accumulate,但它并没有帮助,因为字符串容器只能push_back字符。

int main () {
  using namespace std;
  string str = "Hello, world!";
  vector<string>  vec (10, str);
  // Concatenate here?

  return 0;
}

如何将字符串连接在一起?


1
请考虑将接受的解决方案更改为效率更高的方案。 - einpoklum
5个回答

71

假设这是第6.8题,它并没有说你必须使用accumulate - 它说使用“一个库算法”。然而,你可以使用accumulate:

#include <numeric>
    
int main () {
    std::string str = "Hello World!";
    std::vector<std::string> vec(10,str);
    std::string a = std::accumulate(vec.begin(), vec.end(), std::string(""));
    std::cout << a << std::endl;
}

累加函数所做的只是将“sum”设置为第三个参数,然后对于从第一个参数到第二个参数的所有值“val”,执行以下操作:

sum = sum + val

然后它返回 'sum'。尽管在 <numeric> 中声明了 accumulate,但它适用于任何实现了 operator+() 的东西。


注意这个解决方案虽然优雅,但效率低下,因为对于vec的每个元素都会分配和填充一个新字符串。


谢谢,我尝试使用accumulate函数,并将第三个参数设置为a.begin,但是没有成功。我还尝试了使用back_inserter,但也失败了。你能解释一下这是如何工作的吗?非常感谢。 - Bogdan
1
它将从.begin()到.end()的向量中的每个元素累加到第三个参数中,该参数作为临时传递了一个空的std::string。std::accumulate()的返回值是通过值传递的累加结果。 - John Dibling
3
顺便说一下,这种方法可能会扩展得非常糟糕,因为可能涉及大量的复制/重新分配。 - sellibitze
1
std::reduce (C++17) - more faster than std::accumulate: std::string a = std::reduce(vec.begin(), vec.end(), std::string("")); - Kuznetsov-M

18

std::copy怎么样?

std::ostringstream os;
std::copy( vec_strings.begin(), vec_string.end(), std::ostream_iterator<std::string>( os ) );
std::cout << os.str() << std::endl;

1
你能将这个解决方案与已接受的方案进行比较吗? - einpoklum
接受的答案是O(N^2):https://dev59.com/T2Up5IYBdhLWcg3wVWcG - saurabheights

13

以下代码片段可在Visual C++ 2012中进行编译,并使用了lambda函数:

int main () {
    string str = "Hello World!";
    vector<string>  vec (10,str);

    stringstream ss;
    for_each(vec.begin(), vec.end(), [&ss] (const string& s) { cat(ss, s); });

    cout << ss.str() << endl;
}

第一个回答中的accumulate示例很优雅,但正如sellibitze指出的那样,它每次连接时重新分配并以O(N²)的速度缩放。这个for_each代码片段的缩放大约为O(N)。我使用100K个字符串分别测试了两种解决方案;accumulate示例需要23.6秒,但是这个for_each代码片段只需要0.054秒。


2
创建一个 std::string 并调用 reserve(final-size) 可能会更快,然后只需使用 +=,因为缓冲区已经是正确的大小。 - Alexis Wilke
3
@pixelgrease,什么是“cat函数”?它是如何定义的?谢谢。 - mrchance

8
我不确定你的问题在哪里。问题只是一个循环的问题。
#include<vector>
#include<string>
#include<iostream>

int main () 
{
    std::string str = "Hello World!";
    std::vector<string>  vec (10,str);

    for(size_t i=0;i!=vec.size();++i)
        str=str+vec[i];
    std::cout<<str;
}

编辑:

使用来自<algorithm>for_each()

尝试这个:

#include<vector>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
string i;
void func(string &k)
{
  i+=k;
}
int main () {
    string str = "Hello World!";
    vector<string>  vec (10,str);

    for_each(vec.begin(),vec.end(),func);
    cout<<i;
    return 0;
  }

1
我必须使用algorithm头文件中的函数来完成这个任务。 - Bogdan
问题本身并不太好。xD - Prasoon Saurav
2
使用适当的functor,而不是自由函数,来使用for_each。这样可以避免使用全局变量。 - Glen

0

此答案是对@PrasoonSaurav的改进版本,通过添加有用的sep参数。

inline std::string joinStrings(std::vector<std::string> arr, std::string sep) {
    std::string out = arr[0];
    for(unsigned int i = 1; i < arr.size(); i++) {
        out += sep + arr[i];
    }
    return out;
}

// Overload function parameter to add default value for the separator
inline std::string joinStrings(std::vector<std::string> arr) {
    return joinStrings(arr, std::string(", "));
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接