std :: vector to string with custom delimiter

nki*_*int 27 c++ string vector

我想用自定义分隔符将a的内容复制vector到一个long string.到目前为止,我已经尝试过:

// .h
string getLabeledPointsString(const string delimiter=",");
// .cpp
string Gesture::getLabeledPointsString(const string delimiter) {
    vector<int> x = getLabeledPoints();
    stringstream  s;
    copy(x.begin(),x.end(), ostream_iterator<int>(s,delimiter));
    return s.str();
}
Run Code Online (Sandbox Code Playgroud)

但我明白了

no matching function for call to ‘std::ostream_iterator<int, char, std::char_traits<char> >::ostream_iterator(std::stringstream&, const std::string&)’
Run Code Online (Sandbox Code Playgroud)

我试过charT*但我得到了

error iso c++ forbids declaration of charT with no type
Run Code Online (Sandbox Code Playgroud)

然后我尝试使用char,ostream_iterator<int>(s,&delimiter) 但我在字符串中得到奇怪的字符.

任何人都可以帮助我理解编译器在这里期待什么吗?

jpa*_*cek 22

使用delimiter.c_str()作为分隔符:

copy(x.begin(),x.end(), ostream_iterator<int>(s,delimiter.c_str()));
Run Code Online (Sandbox Code Playgroud)

这样,你得到一个const char*指向字符串,这是你的ostream_operator期望std::string.

  • +1,但请注意,这将在输出中写一个尾随的`delimiter`. (21认同)
  • 我不确定这里的表现。`stringstream` 管理自己的缓冲区,因此它必须动态增长。在这里,您在生成字符串之前就知道它将是什么长度,因此您应该在连接之前保留缓冲区。 (2认同)
  • “在生成字符串之前你知道它的长度” - 或者至少你知道一个上限。如果 stringstream 的缓冲区呈指数增长,那么我就不会担心性能,但我不知道情况是否如此。 (2认同)

max*_*ndr 13

C++ 11:

vector<string> x = {"1", "2", "3"};
string s = std::accumulate(std::begin(x), std::end(x), string(),
                                [](string &ss, string &s)
                                {
                                    return ss.empty() ? s : ss + "," + s;
                                });
Run Code Online (Sandbox Code Playgroud)

  • 看起来很简洁,但是这个过程中不会创建很多字符串吗?有什么办法可以使用字符串流来改进这个吗? (4认同)

Sha*_*531 12

另一种方法:

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
using namespace std;

template <typename T>
string join(const T& v, const string& delim) {
    ostringstream s;
    for (const auto& i : v) {
        if (&i != &v[0]) {
            s << delim;
        }
        s << i;
    }
    return s.str();
}

int main() {
    cout << join(vector<int>({1, 2, 3, 4, 5}), ",") << endl;
}
Run Code Online (Sandbox Code Playgroud)

(c ++ 11基于范围的循环和'自动'虽然)


Mat*_* M. 9

std::string Gesture::getLabeledPointsString(const std::string delimiter) {
  return boost::join(getLabeledPoints(), delimiter);
}
Run Code Online (Sandbox Code Playgroud)

我不相信getLabeledPointsString在这一点上介绍;)


小智 7

这是上面已经提供的两个答案的扩展,因为运行时性能似乎是评论中的主题.我会把它添加为评论,但我还没有这个特权.

我使用Visual Studio 2015测试了2个运行时性能的实现:

使用stringstream:

std::stringstream result;
auto it = vec.begin();
result << (unsigned short)*it++;
for (; it != vec.end(); it++) {
    result << delimiter;
    result << (unsigned short)*it;
}
return result.str();
Run Code Online (Sandbox Code Playgroud)

使用累积:

std::string result = std::accumulate(std::next(vec.begin()), vec.end(),
    std::to_string(vec[0]),
    [&delimiter](std::string& a, uint8_t b) {
    return a + delimiter+ std::to_string(b);
});
return result;
Run Code Online (Sandbox Code Playgroud)

发布版本的运行时性能接近于几个细微之处.

累积实现略快(20-50ms,在256个元素向量的1000次迭代中总运行时间的约10-30%(~180ms)).但是,accumulatealambda函数的参数通过引用传递时,实现速度更快.a按值传递参数导致类似的运行时差异有利于stringstream实现.该accumulate实施也提高了一些,当结果字符串直接返回,而不是分配给立刻返回一个局部变量.YMMV与其他C++编译器.

Debug构建的使用速度慢了5-10倍,accumulate所以我认为上面几条评论中提到的额外字符串创建由优化器解决.

我使用的是寻找一个具体实施vectoruint8_t值.完整的测试代码如下:

#include <vector>
#include <iostream>
#include <sstream>
#include <numeric>
#include <chrono>

using namespace std;
typedef vector<uint8_t> uint8_vec_t;

string concat_stream(const uint8_vec_t& vec, string& delim = string(" "));
string concat_accumulate(const uint8_vec_t& vec, string& delim = string(" "));

string concat_stream(const uint8_vec_t& vec, string& delimiter)
{
    stringstream result;

    auto it = vec.begin();
    result << (unsigned short)*it++;
    for (; it != vec.end(); it++) {
        result << delimiter;
        result << (unsigned short)*it;
    }
    return result.str();
}

string concat_accumulate(const uint8_vec_t& vec, string& delimiter)
{
    return accumulate(next(vec.begin()), vec.end(),
        to_string(vec[0]),
        [&delimiter](string& a, uint8_t b) {
        return a + delimiter + to_string(b);
    });
}

int main()
{
    const int elements(256);
    const int iterations(1000);

    uint8_vec_t test(elements);
    iota(test.begin(), test.end(), 0);

    int i;
    auto stream_start = chrono::steady_clock::now();
    string join_with_stream;
    for (i = 0; i < iterations; ++i) {
        join_with_stream = concat_stream(test);
    }
    auto stream_end = chrono::steady_clock::now();

    auto acc_start = chrono::steady_clock::now();
    string join_with_acc;
    for (i = 0; i < iterations; ++i) {
        join_with_acc = concat_accumulate(test);
    }
    auto acc_end = chrono::steady_clock::now();

    cout << "Stream Results:" << endl;
    cout << "    elements: " << elements << endl;
    cout << "    iterations: " << iterations << endl;
    cout << "    runtime: " << chrono::duration<double, milli>(stream_end - stream_start).count() << " ms" << endl;
    cout << "    result: " << join_with_stream << endl;

    cout << "Accumulate Results:" << endl;
    cout << "    elements: " << elements << endl;
    cout << "    iterations: " << iterations << endl;
    cout << "    runtime: " << chrono::duration<double, milli>(acc_end - acc_start).count() << " ms" << endl;
    cout << "    result:" << join_with_acc << endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)


Gle*_*les 5

string join(const vector<string> & v, const string & delimiter = ",") {
    string out;
    if (auto i = v.begin(), e = v.end(); i != e) {
        out += *i++;
        for (; i != e; ++i) out.append(delimiter).append(*i);
    }
    return out;
}
Run Code Online (Sandbox Code Playgroud)

几点:

  • 您不需要额外的条件来避免额外的尾随定界符
  • 确保向量为空时不会崩溃
  • 不要制作一堆临时变量(例如不要这样做:x = x + d + y)