Je cherche la manière la plus élégante d’imploser un vecteur de chaînes dans une chaîne. Voici la solution que j’utilise maintenant:
static std::ssortingng& implode(const std::vector& elems, char delim, std::ssortingng& s) { for (std::vector::const_iterator ii = elems.begin(); ii != elems.end(); ++ii) { s += (*ii); if ( ii + 1 != elems.end() ) { s += delim; } } return s; } static std::ssortingng implode(const std::vector& elems, char delim) { std::ssortingng s; return implode(elems, delim, s); }
Y a-t-il d’autres là-bas?
Utilisez boost::algorithm::join(..)
:
#include ... std::ssortingng joinedSsortingng = boost::algorithm::join(elems, delim);
Voir aussi cette question .
std::vector ssortingngs; const char* const delim = ", "; std::ossortingngstream imploded; std::copy(ssortingngs.begin(), ssortingngs.end(), std::ostream_iterator (imploded, delim));
(inclure
,
,
et
)
Si vous voulez avoir une fin propre (pas de délimiteur de fin), regardez ici
Vous devez utiliser std::ossortingngstream
plutôt que std::ssortingng
pour générer la sortie (vous pouvez alors appeler sa méthode str()
à la fin pour obtenir une chaîne, votre interface n’a donc pas besoin de changer, seulement les s
temporaires).
À partir de là, vous pouvez utiliser std::ostream_iterator
, comme ceci:
copy(elems.begin(), elems.end(), ostream_iterator(s, delim));
Mais cela a deux problèmes:
delim
doit maintenant être un const char*
plutôt qu’un simple caractère. Pas grand chose std::ostream_iterator
écrit le délimiteur après chaque élément, y compris le dernier. Donc, vous devez soit effacer le dernier à la fin, soit écrire votre propre version de l’iterator qui n’a pas cette gêne. Cela vaut la peine de faire ce dernier si vous avez beaucoup de code qui a besoin de choses comme ça; Sinon, il serait préférable d’éviter tout le désordre (utiliser ossortingngstream
mais pas ostream_iterator
). Parce que j’aime les one-liners (ils sont très utiles pour toutes sortes de choses bizarres, comme vous le verrez à la fin), voici une solution avec std :: accumulate et C ++ 11 lambda:
std::accumulate(alist.begin(), alist.end(), std::ssortingng(), [](const std::ssortingng& a, const std::ssortingng& b) -> std::ssortingng { return a + (a.length() > 0 ? "," : "") + b; } )
Je trouve cette syntaxe utile avec l’opérateur de stream, où je ne veux pas avoir toutes sortes de logique étrange hors de scope de l’opération de stream, juste pour faire une simple jointure de chaîne. Considérons par exemple cette déclaration de retour de la méthode qui formate une chaîne à l’aide des opérateurs de stream (en utilisant std;):
return (dynamic_cast(ossortingngstream() << "List content: " << endl << std::accumulate(alist.begin(), alist.end(), std::string(), [](const std::string& a, const std::string& b) -> std::ssortingng { return a + (a.length() > 0 ? "," : "") + b; } ) << endl << "Maybe some more stuff" << endl )).str();
ssortingng join(const vector& vec, const char* delim) { ssortingngstream res; copy(vec.begin(), vec.end(), ostream_iterator (res, delim)); return res.str(); }
Une version utilisant std::accumulate
:
#include #include #include struct infix { std::ssortingng sep; infix(const std::ssortingng& sep) : sep(sep) {} std::ssortingng operator()(const std::ssortingng& lhs, const std::ssortingng& rhs) { std::ssortingng rz(lhs); if(!lhs.empty() && !rhs.empty()) rz += sep; rz += rhs; return rz; } }; int main() { std::ssortingng a[] = { "Hello", "World", "is", "a", "program" }; std::ssortingng sum = std::accumulate(a, a+5, std::ssortingng(), infix(", ")); std::cout << sum << "\n"; }
Voici un autre qui n’ajoute pas le délimiteur après le dernier élément:
std::ssortingng concat_ssortingngs(const std::vector &elements, const std::ssortingng &separator) { if (!elements.empty()) { std::ssortingngstream ss; auto it = elements.cbegin(); while (true) { ss << *it++; if (it != elements.cend()) ss << separator; else return ss.str(); } } return "";
Surtout avec les plus grandes collections, vous devez éviter de vérifier si vous ajoutez encore le premier élément ou ne pas vous assurer de séparateur de fin.
Donc, pour la liste vide ou mono-élément, il n’y a pas d’itération du tout.
Les plages vides sont sortingviales: retourner “”.
Un seul élément ou multi-élément peut être manipulé parfaitement en accumulate
:
auto join = [](const auto &&range, const auto separator) { if (range.empty()) return std::ssortingng(); return std::accumulate( next(begin(range)), // there is at least 1 element, so OK. end(range), range[0], // the initial value [&separator](auto result, const auto &value) { return result + separator + value; }); };
Exemple en cours d’exécution ( nécessite C ++ 14 ): http://cpp.sh/8uspd
Qu’en est-il d’une solution simple et stupide?
std::ssortingng Ssortingng::join(const std::vector &lst, const std::ssortingng &delim) { std::ssortingng ret; for(const auto &s : lst) { if(!ret.empty()) ret += delim; ret += s; } return ret; }
Solution légèrement longue, mais n’utilise pas std::ossortingngstream
, et ne nécessite pas de hack pour supprimer le dernier délimiteur.
Et le code:
struct appender { appender(char d, std::ssortingng& sd, int ic) : delim(d), dest(sd), count(ic) { dest.reserve(2048); } void operator()(std::ssortingng const& copy) { dest.append(copy); if (--count) dest.append(1, delim); } char delim; mutable std::ssortingng& dest; mutable int count; }; void implode(const std::vector& elems, char delim, std::ssortingng& s) { std::for_each(elems.begin(), elems.end(), appender(delim, s, elems.size())); }
Ajoutez simplement !! Ssortingng s = “”;
for (int i = 0; i < doc.size(); i++) //doc is the vector s += doc[i];
Voici ce que j’utilise, simple et flexible
ssortingng joinList(vector arr, ssortingng delimiter) { if (arr.empty()) return ""; ssortingng str; for (auto i : arr) str += i + delimiter; str = str.substr(0, str.size() - delimiter.size()); return str; }
en utilisant:
ssortingng a = joinList({ "a", "bbb", "c" }, "!@#");
sortie:
a!@#bbb!@#c
Tout d’abord, une classe de stream ossortingngstream
est nécessaire ici pour faire la concaténation plusieurs fois et sauver le problème sous-jacent d’une allocation de mémoire excessive.
Code:
ssortingng join(const vector& vec, const char* delim) { ossortingngstream oss; if(!ssortingng_vector.empty()) { copy(ssortingng_vector.begin(),ssortingng_vector.end() - 1, ostream_iterator (oss, delim.c_str())); } return oss.str(); } vector ssortingng_vector {"1", "2"}; ssortingng delim("->"); ssortingng joined_ssortingng = join(); // get "1->2"
Explication:
en pensant, traitez oss
ici comme std::cout
quand on veut écrire:
std::cout << string_vector[0] << "->" << string_vector[1] << "->"
,
nous pouvons utiliser les classes STL suivantes comme aide:
ostream_iterator
renvoie un stream de sortie ostream_iterator
avec des délimiteurs ajoutés automatiquement chaque fois que vous utilisez <<
.
par exemple,
ostream my_cout = ostream_iterator
wraps std:cout
comme my_cout
donc à chaque fois que vous my_cout << "string_vector[0]"
,
cela signifie std::cout << "string_vector[0]" << "->"
Comme pour la copy(vector.begin(), vector.end(), std::out);
cela signifie std::cout << vector[0] << vector[1] (...) << vector[end]
Essayez ceci, mais en utilisant le vecteur au lieu de la liste
template std::ssortingng listToSsortingng(std::list l){ std::ssortingngstream ss; for(std::list::iterator it = l.begin(); it!=l.end(); ++it){ ss << *it; if(std::distance(it,l.end())>1) ss << ", "; } return "[" + ss.str()+ "]"; }
En utilisant une partie de cette réponse à une autre question, vous vous joignez à ceci, basé sur un séparateur sans virgule finale,
Usage:
std::vector input_str = std::vector ({"a", "b", "c"}); std::ssortingng result = ssortingng_join(input_str, ","); printf("%s", result.c_str()); /// a,b,c
Code:
std::ssortingng ssortingng_join(const std::vector& elements, const char* const separator) { switch (elements.size()) { case 0: return ""; case 1: return elements[0]; default: std::ossortingngstream os; std::copy(elements.begin(), elements.end() - 1, std::ostream_iterator (os, separator)); os << *elements.rbegin(); return os.str(); } }