I know how to do this in other languages, but not C++, which I am forced to use here.
I have a Set of Strings that I\'m printing to out in a list, and they need a co
Another possible solution, which avoids an if
Char comma = '[';
for (const auto& element : elements) {
std::cout.put(comma) << element;
comma = ',';
}
std::cout.put(']');
Depends what you're doing in your loop.
If the values are std::string
s you can write this nicely in a declarative style with range-v3
#include <range/v3/all.hpp>
#include <vector>
#include <iostream>
#include <string>
int main()
{
using namespace ranges;
std::vector<std::string> const vv = { "a","b","c" };
auto joined = vv | view::join(',');
std::cout << to_<std::string>(joined) << std::endl;
}
For other types which have to be converted to string you can just add a transformation calling to_string
.
#include <range/v3/all.hpp>
#include <vector>
#include <iostream>
#include <string>
int main()
{
using namespace ranges;
std::vector<int> const vv = { 1,2,3 };
auto joined = vv | view::transform([](int x) {return std::to_string(x);})
| view::join(',');
std::cout << to_<std::string>(joined) << std::endl;
}
Could be like so..
bool bFirst = true;
for (auto curr = keywords.begin(); curr != keywords.end(); ++curr) {
std::cout << (bFirst ? "" : ", ") << *curr;
bFirst = false;
}
I use a little helper class for that:
class text_separator {
public:
text_separator(const char* sep) : sep(sep), needsep(false) {}
// returns an empty string the first time it is called
// returns the provided separator string every other time
const char* operator()() {
if (needsep)
return sep;
needsep = true;
return "";
}
void reset() { needsep = false; }
private:
const char* sep;
bool needsep;
};
To use it:
text_separator sep(", ");
for (int i = 0; i < 10; ++i)
cout << sep() << i;
Here are two methods you could use, which are both essentially the same idea. I like these methods because they do not contain any unnecessary conditional checks or assignment operations. I'll call the first one the print first method.
if (!keywords.empty()) {
out << *(keywords.begin()); // First element.
for (auto it = ++(keywords.begin()); it != keywords.end(); it++)
out << ", " << *it; // Every subsequent element.
}
This is the method I used at first. It works by printing the first element in your container by itself, and then prints every subsequent element preceded by a comma and space. It's simple, concise, and works great if that's all you need it to do. Once you want to do more things, like add an "and" before the last element, this method falls short. You'd have to check each loop iteration for if it's on the last element. Adding a period, or newline after the list wouldn't be so bad, though. You could just add one more line after the for-loop to append whatever you desire to the list.
The second method I like a lot more. That one I'll call the print last method, as it does the same thing as the first but in reverse order.
if (!keywords.empty()) {
auto it = keywords.begin(), last = std::prev(keywords.end());
for (; it != last; it++) // Every preceding element.
out << *it << ", ";
out << "and " << *it << ".\n"; // Last element.
}
This one works by printing every element except for the last with a comma and space, allowing you to optionally add an "and" before it, a period after it, and/or a newline character. As you can see, this method gives you a lot more options on how you can handle that last element without affecting the performance of the loop or adding much code.
If it bothers you to leave the first part of the for-loop empty, you could write it like so:
if (!keywords.empty()) {
auto it, last;
for (it = keywords.begin(), last = std::prev(keywords.end()); it != last; it++)
out << *it << ", ";
out << "and " << *it << ".\n";
}
Try this:
typedef std::vector<std::string> Container;
typedef Container::const_iterator CIter;
Container data;
// Now fill the container.
// Now print the container.
// The advantage of this technique is that ther is no extra test during the loop.
// There is only one additional test !test.empty() done at the beginning.
if (!data.empty())
{
std::cout << data[0];
for(CIter loop = data.begin() + 1; loop != data.end(); ++loop)
{
std::cout << "," << *loop;
}
}