Je voudrais copier le contenu d'un vector
dans un long string
avec un délimiteur personnalisé. Jusqu'à présent, j'ai essayé:
// .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();
}
mais je reçois
no matching function for call to ‘std::ostream_iterator<int, char, std::char_traits<char> >::ostream_iterator(std::stringstream&, const std::string&)’
J'ai essayé avec charT*
Mais je reçois
error iso c++ forbids declaration of charT with no type
J'ai ensuite essayé d'utiliser char
et ostream_iterator<int>(s,&delimiter)
mais j'obtiens des caractères étranges dans la chaîne.
Quelqu'un peut-il m'aider à comprendre ce que le compilateur attend ici?
tilisez delimiter.c_str()
comme délimiteur :
copy(x.begin(),x.end(), ostream_iterator<int>(s,delimiter.c_str()));
De cette façon, vous obtenez un const char*
pointant vers la chaîne, c'est ce que ostream_operator
attend de votre std::string
.
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;
});
Une autre façon de procéder:
#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;
}
(basé sur la plage c ++ 11 pour la boucle et 'auto' cependant)
std::string Gesture::getLabeledPointsString(const std::string delimiter) {
return boost::join(getLabeledPoints(), delimiter);
}
Je ne suis pas convaincu de l'introduction de getLabeledPointsString
à ce stade;)
Il s'agit d'une extension des deux réponses déjà fournies ci-dessus, car les performances d'exécution semblaient être un thème dans les commentaires. Je l'aurais ajouté comme commentaires, mais je n'ai pas encore ce privilège.
J'ai testé 2 implémentations pour les performances d'exécution à l'aide de Visual Studio 2015:
Utilisation de 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();
Utilisation d'accumuler:
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;
Les performances d'exécution de la version finale étaient proches avec quelques subtilités.
L'implémentation cumulée était légèrement plus rapide (20-50 ms, ~ 10-30% du temps d'exécution global (~ 180 ms) sur 1000 itérations sur un vecteur à 256 éléments). Cependant, l'implémentation accumulate
n'était plus rapide que lorsque le paramètre a
à la fonction lambda était passé par référence. Le passage du paramètre a
par valeur a entraîné une différence d'exécution similaire favorisant l'implémentation stringstream
. L'implémentation accumulate
a également été améliorée lorsque la chaîne de résultat a été retournée directement plutôt qu'attribuée à une variable locale qui a été immédiatement renvoyée. YMMV avec d'autres compilateurs C++.
La construction du débogage a été 5 à 10 fois plus lente en utilisant accumulate
donc je pense que la création de chaîne supplémentaire notée dans plusieurs commentaires ci-dessus est résolue par l'optimiseur.
Je cherchais une implémentation spécifique en utilisant un vector
de uint8_t
valeurs. Le code de test complet suit:
#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;
}
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;
}
Quelques points:
int array[ 6 ] = { 1, 2, 3, 4, 5, 6 };
std::vector< int > a( array, array + 6 );
stringstream dataString;
ostream_iterator<int> output_iterator(dataString, ";"); // here ";" is delimiter
std::copy(a.begin(), a.end(), output_iterator);
cout<<dataString.str()<<endl;
sortie = 1; 2; 3; 4; 5; 6;