I know how to do this in other languages, but not in C++, which I am forced to use here.
I have a set of strings (keywords) that I'm printing to out as a list, and the strings need a comma between them, but not a trailing comma. In Java, for instance, I would use a StringBuilder and just delete the comma off the end after I've built my string. How can I do it in C++?
auto iter = keywords.begin();
for (iter; iter != keywords.end( ); iter++ )
{
out << *iter << ", ";
}
out << endl;
I initially tried inserting the following block to do it (moving the comma printing here):
if (iter++ != keywords.end())
out << ", ";
iter--;
Use an infix_iterator:
// infix_iterator.h
//
// Lifted from Jerry Coffin's 's prefix_ostream_iterator
#if !defined(INFIX_ITERATOR_H_)
#define INFIX_ITERATOR_H_
#include <ostream>
#include <iterator>
template <class T,
class charT=char,
class traits=std::char_traits<charT> >
class infix_ostream_iterator :
public std::iterator<std::output_iterator_tag,void,void,void,void>
{
std::basic_ostream<charT,traits> *os;
charT const* delimiter;
bool first_elem;
public:
typedef charT char_type;
typedef traits traits_type;
typedef std::basic_ostream<charT,traits> ostream_type;
infix_ostream_iterator(ostream_type& s)
: os(&s),delimiter(0), first_elem(true)
{}
infix_ostream_iterator(ostream_type& s, charT const *d)
: os(&s),delimiter(d), first_elem(true)
{}
infix_ostream_iterator<T,charT,traits>& operator=(T const &item)
{
// Here's the only real change from ostream_iterator:
// Normally, the '*os << item;' would come before the 'if'.
if (!first_elem && delimiter != 0)
*os << delimiter;
*os << item;
first_elem = false;
return *this;
}
infix_ostream_iterator<T,charT,traits> &operator*() {
return *this;
}
infix_ostream_iterator<T,charT,traits> &operator++() {
return *this;
}
infix_ostream_iterator<T,charT,traits> &operator++(int) {
return *this;
}
};
#endif
Usage would be something like:
#include "infix_iterator.h"
// ...
std::copy(keywords.begin(), keywords.end(), infix_iterator(out, ","));
In an experimental C++17 ready compiler coming soon to you, you can use std::experimental::ostream_joiner:
#include <algorithm>
#include <experimental/iterator>
#include <iostream>
#include <iterator>
int main()
{
int i[] = {1, 2, 3, 4, 5};
std::copy(std::begin(i),
std::end(i),
std::experimental::make_ostream_joiner(std::cout, ", "));
}
Live examples using GCC 6.0 SVN and Clang 3.9 SVN
Because everyone has decided to do this with while loops, I'll give an example with for loops.
for (iter = keywords.begin(); iter != keywords.end(); iter++) {
if (iter != keywords.begin()) cout << ", ";
cout << *iter;
}
Assuming a vaguely normal output stream, so that writing an empty string to it does indeed do nothing:
const char *padding = "";
for (auto iter = keywords.begin(); iter != keywords.end(); ++iter) {
out << padding << *iter;
padding = ", "
}
One common approach is to print the first item prior to the loop, and loop only over the remaining items, PRE-printing a comma before each remaining item.
Alternately you should be able to create your own stream that maintains a current state of the line (before endl) and puts commas in the appropriate place.
EDIT:
You can also use a middle-tested loop as suggested by T.E.D. It would be something like:
if(!keywords.empty())
{
auto iter = keywords.begin();
while(true)
{
out << *iter;
++iter;
if(iter == keywords.end())
{
break;
}
else
{
out << ", ";
}
}
}
I mentioned the "print first item before loop" method first because it keeps the loop body really simple, but any of the approaches work fine.
There are lots of clever solutions, and too many that mangle the code beyond hope of salvation without letting the compiler do its job.
The obvious solution, is to special-case the first iteration:
bool first = true;
for (auto const& e: sequence) {
if (first) { first = false; } else { out << ", "; }
out << e;
}
It's a dead simple pattern which:
Does not mangle the loop: it's still obvious at a glance that each element will be iterated on.
Allows more than just putting a separator, or actually printing a list, as the else block and the loop body can contain arbitrary statements.
It may not be the absolutely most efficient code, but the potential performance loss of a single well-predicted branch is very likely to be overshadowed by the massive behemoth that is std::ostream::operator<<.
Something like this?
while (iter != keywords.end())
{
out << *iter;
iter++;
if (iter != keywords.end()) cout << ", ";
}
My typical method for doing separators (in any language) is to use a mid-tested loop. The C++ code would be:
for (;;) {
std::cout << *iter;
if (++iter == keywords.end()) break;
std::cout << ",";
}
(note: An extra if check is needed prior to the loop if keywords may be empty)
Most of the other solutions shown end up doing an entire extra test every loop iteration. You are doing I/O, so the time taken by that isn't a huge problem, but it offends my sensibilities.
In python we just write:
print ", ".join(keywords)
so why not:
template<class S, class V>
std::string
join(const S& sep, const V& v)
{
std::ostringstream oss;
if (!v.empty()) {
typename V::const_iterator it = v.begin();
oss << *it++;
for (typename V::const_iterator e = v.end(); it != e; ++it)
oss << sep << *it;
}
return oss.str();
}
and then just use it like:
cout << join(", ", keywords) << endl;
Unlike in the python example above where the " " is a string and the keywords has to be an iterable of strings, here in this C++ example the separator and keywords can be anything streamable, e.g.
cout << join('\n', keywords) << endl;
I suggest you simply switch the first character with the help of a lambda.
std::function<std::string()> f = [&]() {f = [](){ return ","; }; return ""; };
for (auto &k : keywords)
std::cout << f() << k;
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;
}
}
to avoid placing an if inside the loop, I use this:
vector<int> keywords = {1, 2, 3, 4, 5};
if (!keywords.empty())
{
copy(keywords.begin(), std::prev(keywords.end()),
std::ostream_iterator<int> (std::cout,", "));
std::cout << keywords.back();
}
It depends on the vector type, int, but you can remove it with some helper.
If the values are std::strings 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;
}
There is a little problem with the ++ operator you are using.
You can try:
if (++iter != keywords.end())
out << ", ";
iter--;
This way, ++ will be evaluated before compare the iterator with keywords.end().
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;
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.
Following should do:-
const std::vector<__int64>& a_setRequestId
std::stringstream strStream;
std::copy(a_setRequestId.begin(), a_setRequestId.end() -1, std::ostream_iterator<__int64>(strStream, ", "));
strStream << a_setRequestId.back();
I think this variant of #MarkB's answer strikes optimal balance of readability, simplicity and terseness:
auto iter= keywords.begin();
if (iter!=keywords.end()) {
out << *iter;
while(++iter != keywords.end())
out << "," << *iter;
}
out << endl;
It's very easy to fix that (taken from my answer here):
bool print_delim = false;
for (auto iter = keywords.begin(); iter != keywords.end( ); iter++ ) {
if(print_delim) {
out << ", ";
}
out << *iter;
print_delim = true;
}
out << endl;
I am using this idiom (pattern?) in many programming languages, and all kind of tasks where you need to construct delimited output from list like inputs. Let me give the abstract in pseudo code:
empty output
firstIteration = true
foreach item in list
if firstIteration
add delimiter to output
add item to output
firstIteration = false
In some cases one could even omit the firstIteration indicator variable completely:
empty output
foreach item in list
if not is_empty(output)
add delimiter to output
add item to output
I think simplicity is better for me, so after I look through all answers I prepared my solution(c++14 required):
#include <iostream>
#include <vector>
#include <utility> // for std::exchange c++14
int main()
{
std::vector nums{1, 2, 3, 4, 5}; // c++17
const char* delim = "";
for (const auto value : nums)
{
std::cout << std::exchange(delim, ", ") << value;
}
}
Output example:
1, 2, 3, 4, 5
I think this should work
while (iter != keywords.end( ))
{
out << *iter;
iter++ ;
if (iter != keywords.end( )) out << ", ";
}
Using boost:
std::string add_str("");
const std::string sep(",");
for_each(v.begin(), v.end(), add_str += boost::lambda::ret<std::string>(boost::lambda::_1 + sep));
and you obtain a string containing the vector, comma delimited.
EDIT:
to remove the last comma, just issue:
add_str = add_str.substr(0, add_str.size()-1);
Could be like so..
bool bFirst = true;
for (auto curr = keywords.begin(); curr != keywords.end(); ++curr) {
std::cout << (bFirst ? "" : ", ") << *curr;
bFirst = false;
}
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.
Method 1: 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.
Method 2: the print last method
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";
}
I would go with something like this, an easy solution and should work for all iterators.
int maxele = maxele = v.size() - 1;
for ( cur = v.begin() , i = 0; i < maxele ; ++i)
{
std::cout << *cur++ << " , ";
}
if ( maxele >= 0 )
{
std::cout << *cur << std::endl;
}
You can use a do loop, rewrite the loop condition for the first iteration, and use the short-circuit && operator and the fact that a valid stream is true.
auto iter = keywords.begin();
if ( ! keywords.empty() ) do {
out << * iter;
} while ( ++ iter != keywords.end() && out << ", " );
out << endl;
This one overloads the stream operator. Yes global variables are evil.
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
int index = 0;
template<typename T, template <typename, typename> class Cont>
std::ostream& operator<<(std::ostream& os, const Cont<T, std::allocator<T>>& vec)
{
if (index < vec.size()) {
if (index + 1 < vec.size())
return os << vec[index++] << "-" << vec;
else
return os << vec[index++] << vec;
} else return os;
}
int main()
{
std::vector<int> nums(10);
int n{0};
std::generate(nums.begin(), nums.end(), [&]{ return n++; });
std::cout << nums << std::endl;
}
Can use functors:
#include <functional>
string getSeparatedValues(function<bool()> condition, function<string()> output, string separator)
{
string out;
out += output();
while (condition())
out += separator + output();
return out;
}
Example:
if (!keywords.empty())
{
auto iter = keywords.begin();
cout << getSeparatedValues([&]() { return ++iter != keywords.end(); }, [&]() { return *iter; }, ", ") << endl;
}
A combination of c++11 lambda and macro:
#define INFIX_PRINTER(os, sep)([&]()->decltype(os)&{static int f=1;os<<(f?(f=0,""):sep);return os;})()
Usage:
for(const auto& k: keywords)
INFIX_PRINTER(out, ", ") << k;
I like a range-based for with a is_last_elem test. That imho it's very readable:
for (auto& e : range)
{
if (!is_last_elem(e, range)) [[likely]]
os << e << ", ";
else
os << e;
}
os << std::endl;
Full code:
C++20:
#include <iostream>
#include <list>
#include <ranges>
#include <utility>
#include <type_traits>
#include <memory>
template <std::ranges::bidirectional_range R>
bool is_last_elem(const std::ranges::range_value_t<R>& elem, const R& range)
{
auto last_it = range.end();
std::advance(last_it, -1);
return std::addressof(elem) == std::addressof(*last_it);
}
template <std::ranges::bidirectional_range R, class Stream = std::ostream>
void print(const R& range, std::ostream& os = std::cout)
{
for (auto& e : range)
{
if (!is_last_elem(e, range)) [[likely]]
os << e << ", ";
else
os << e;
}
os << std::endl;
}
int main()
{
std::list<int> v{1, 2, 3, 4, 5};
print(v);
}
C++17:
#include <iostream>
#include <list>
#include <utility>
#include <type_traits>
#include <memory>
template <class Range>
using value_type_t = std::remove_reference_t<decltype(*std::begin(std::declval<Range>()))>;
template <class Range>
bool is_last_elem(const value_type_t<Range>& elem, const Range& range)
{
auto last_it = range.end();
std::advance(last_it, -1);
return std::addressof(elem) == std::addressof(*last_it);
}
template <class Range, class Stream = std::ostream>
void print(const Range& range, std::ostream& os = std::cout)
{
for (auto& e : range)
{
if (!is_last_elem(e, range))
os << e << ", ";
else
os << e;
}
os << std::endl;
}
int main()
{
std::list<int> v{1, 2, 3, 4, 5};
print(v);
}
Related
I know how to do this in other languages, but not in C++, which I am forced to use here.
I have a set of strings (keywords) that I'm printing to out as a list, and the strings need a comma between them, but not a trailing comma. In Java, for instance, I would use a StringBuilder and just delete the comma off the end after I've built my string. How can I do it in C++?
auto iter = keywords.begin();
for (iter; iter != keywords.end( ); iter++ )
{
out << *iter << ", ";
}
out << endl;
I initially tried inserting the following block to do it (moving the comma printing here):
if (iter++ != keywords.end())
out << ", ";
iter--;
Use an infix_iterator:
// infix_iterator.h
//
// Lifted from Jerry Coffin's 's prefix_ostream_iterator
#if !defined(INFIX_ITERATOR_H_)
#define INFIX_ITERATOR_H_
#include <ostream>
#include <iterator>
template <class T,
class charT=char,
class traits=std::char_traits<charT> >
class infix_ostream_iterator :
public std::iterator<std::output_iterator_tag,void,void,void,void>
{
std::basic_ostream<charT,traits> *os;
charT const* delimiter;
bool first_elem;
public:
typedef charT char_type;
typedef traits traits_type;
typedef std::basic_ostream<charT,traits> ostream_type;
infix_ostream_iterator(ostream_type& s)
: os(&s),delimiter(0), first_elem(true)
{}
infix_ostream_iterator(ostream_type& s, charT const *d)
: os(&s),delimiter(d), first_elem(true)
{}
infix_ostream_iterator<T,charT,traits>& operator=(T const &item)
{
// Here's the only real change from ostream_iterator:
// Normally, the '*os << item;' would come before the 'if'.
if (!first_elem && delimiter != 0)
*os << delimiter;
*os << item;
first_elem = false;
return *this;
}
infix_ostream_iterator<T,charT,traits> &operator*() {
return *this;
}
infix_ostream_iterator<T,charT,traits> &operator++() {
return *this;
}
infix_ostream_iterator<T,charT,traits> &operator++(int) {
return *this;
}
};
#endif
Usage would be something like:
#include "infix_iterator.h"
// ...
std::copy(keywords.begin(), keywords.end(), infix_iterator(out, ","));
In an experimental C++17 ready compiler coming soon to you, you can use std::experimental::ostream_joiner:
#include <algorithm>
#include <experimental/iterator>
#include <iostream>
#include <iterator>
int main()
{
int i[] = {1, 2, 3, 4, 5};
std::copy(std::begin(i),
std::end(i),
std::experimental::make_ostream_joiner(std::cout, ", "));
}
Live examples using GCC 6.0 SVN and Clang 3.9 SVN
Because everyone has decided to do this with while loops, I'll give an example with for loops.
for (iter = keywords.begin(); iter != keywords.end(); iter++) {
if (iter != keywords.begin()) cout << ", ";
cout << *iter;
}
Assuming a vaguely normal output stream, so that writing an empty string to it does indeed do nothing:
const char *padding = "";
for (auto iter = keywords.begin(); iter != keywords.end(); ++iter) {
out << padding << *iter;
padding = ", "
}
One common approach is to print the first item prior to the loop, and loop only over the remaining items, PRE-printing a comma before each remaining item.
Alternately you should be able to create your own stream that maintains a current state of the line (before endl) and puts commas in the appropriate place.
EDIT:
You can also use a middle-tested loop as suggested by T.E.D. It would be something like:
if(!keywords.empty())
{
auto iter = keywords.begin();
while(true)
{
out << *iter;
++iter;
if(iter == keywords.end())
{
break;
}
else
{
out << ", ";
}
}
}
I mentioned the "print first item before loop" method first because it keeps the loop body really simple, but any of the approaches work fine.
There are lots of clever solutions, and too many that mangle the code beyond hope of salvation without letting the compiler do its job.
The obvious solution, is to special-case the first iteration:
bool first = true;
for (auto const& e: sequence) {
if (first) { first = false; } else { out << ", "; }
out << e;
}
It's a dead simple pattern which:
Does not mangle the loop: it's still obvious at a glance that each element will be iterated on.
Allows more than just putting a separator, or actually printing a list, as the else block and the loop body can contain arbitrary statements.
It may not be the absolutely most efficient code, but the potential performance loss of a single well-predicted branch is very likely to be overshadowed by the massive behemoth that is std::ostream::operator<<.
Something like this?
while (iter != keywords.end())
{
out << *iter;
iter++;
if (iter != keywords.end()) cout << ", ";
}
My typical method for doing separators (in any language) is to use a mid-tested loop. The C++ code would be:
for (;;) {
std::cout << *iter;
if (++iter == keywords.end()) break;
std::cout << ",";
}
(note: An extra if check is needed prior to the loop if keywords may be empty)
Most of the other solutions shown end up doing an entire extra test every loop iteration. You are doing I/O, so the time taken by that isn't a huge problem, but it offends my sensibilities.
In python we just write:
print ", ".join(keywords)
so why not:
template<class S, class V>
std::string
join(const S& sep, const V& v)
{
std::ostringstream oss;
if (!v.empty()) {
typename V::const_iterator it = v.begin();
oss << *it++;
for (typename V::const_iterator e = v.end(); it != e; ++it)
oss << sep << *it;
}
return oss.str();
}
and then just use it like:
cout << join(", ", keywords) << endl;
Unlike in the python example above where the " " is a string and the keywords has to be an iterable of strings, here in this C++ example the separator and keywords can be anything streamable, e.g.
cout << join('\n', keywords) << endl;
I suggest you simply switch the first character with the help of a lambda.
std::function<std::string()> f = [&]() {f = [](){ return ","; }; return ""; };
for (auto &k : keywords)
std::cout << f() << k;
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;
}
}
to avoid placing an if inside the loop, I use this:
vector<int> keywords = {1, 2, 3, 4, 5};
if (!keywords.empty())
{
copy(keywords.begin(), std::prev(keywords.end()),
std::ostream_iterator<int> (std::cout,", "));
std::cout << keywords.back();
}
It depends on the vector type, int, but you can remove it with some helper.
If the values are std::strings 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;
}
There is a little problem with the ++ operator you are using.
You can try:
if (++iter != keywords.end())
out << ", ";
iter--;
This way, ++ will be evaluated before compare the iterator with keywords.end().
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;
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.
Following should do:-
const std::vector<__int64>& a_setRequestId
std::stringstream strStream;
std::copy(a_setRequestId.begin(), a_setRequestId.end() -1, std::ostream_iterator<__int64>(strStream, ", "));
strStream << a_setRequestId.back();
I think this variant of #MarkB's answer strikes optimal balance of readability, simplicity and terseness:
auto iter= keywords.begin();
if (iter!=keywords.end()) {
out << *iter;
while(++iter != keywords.end())
out << "," << *iter;
}
out << endl;
It's very easy to fix that (taken from my answer here):
bool print_delim = false;
for (auto iter = keywords.begin(); iter != keywords.end( ); iter++ ) {
if(print_delim) {
out << ", ";
}
out << *iter;
print_delim = true;
}
out << endl;
I am using this idiom (pattern?) in many programming languages, and all kind of tasks where you need to construct delimited output from list like inputs. Let me give the abstract in pseudo code:
empty output
firstIteration = true
foreach item in list
if firstIteration
add delimiter to output
add item to output
firstIteration = false
In some cases one could even omit the firstIteration indicator variable completely:
empty output
foreach item in list
if not is_empty(output)
add delimiter to output
add item to output
I think simplicity is better for me, so after I look through all answers I prepared my solution(c++14 required):
#include <iostream>
#include <vector>
#include <utility> // for std::exchange c++14
int main()
{
std::vector nums{1, 2, 3, 4, 5}; // c++17
const char* delim = "";
for (const auto value : nums)
{
std::cout << std::exchange(delim, ", ") << value;
}
}
Output example:
1, 2, 3, 4, 5
I think this should work
while (iter != keywords.end( ))
{
out << *iter;
iter++ ;
if (iter != keywords.end( )) out << ", ";
}
Using boost:
std::string add_str("");
const std::string sep(",");
for_each(v.begin(), v.end(), add_str += boost::lambda::ret<std::string>(boost::lambda::_1 + sep));
and you obtain a string containing the vector, comma delimited.
EDIT:
to remove the last comma, just issue:
add_str = add_str.substr(0, add_str.size()-1);
Could be like so..
bool bFirst = true;
for (auto curr = keywords.begin(); curr != keywords.end(); ++curr) {
std::cout << (bFirst ? "" : ", ") << *curr;
bFirst = false;
}
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.
Method 1: 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.
Method 2: the print last method
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";
}
I would go with something like this, an easy solution and should work for all iterators.
int maxele = maxele = v.size() - 1;
for ( cur = v.begin() , i = 0; i < maxele ; ++i)
{
std::cout << *cur++ << " , ";
}
if ( maxele >= 0 )
{
std::cout << *cur << std::endl;
}
You can use a do loop, rewrite the loop condition for the first iteration, and use the short-circuit && operator and the fact that a valid stream is true.
auto iter = keywords.begin();
if ( ! keywords.empty() ) do {
out << * iter;
} while ( ++ iter != keywords.end() && out << ", " );
out << endl;
This one overloads the stream operator. Yes global variables are evil.
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
int index = 0;
template<typename T, template <typename, typename> class Cont>
std::ostream& operator<<(std::ostream& os, const Cont<T, std::allocator<T>>& vec)
{
if (index < vec.size()) {
if (index + 1 < vec.size())
return os << vec[index++] << "-" << vec;
else
return os << vec[index++] << vec;
} else return os;
}
int main()
{
std::vector<int> nums(10);
int n{0};
std::generate(nums.begin(), nums.end(), [&]{ return n++; });
std::cout << nums << std::endl;
}
Can use functors:
#include <functional>
string getSeparatedValues(function<bool()> condition, function<string()> output, string separator)
{
string out;
out += output();
while (condition())
out += separator + output();
return out;
}
Example:
if (!keywords.empty())
{
auto iter = keywords.begin();
cout << getSeparatedValues([&]() { return ++iter != keywords.end(); }, [&]() { return *iter; }, ", ") << endl;
}
A combination of c++11 lambda and macro:
#define INFIX_PRINTER(os, sep)([&]()->decltype(os)&{static int f=1;os<<(f?(f=0,""):sep);return os;})()
Usage:
for(const auto& k: keywords)
INFIX_PRINTER(out, ", ") << k;
I like a range-based for with a is_last_elem test. That imho it's very readable:
for (auto& e : range)
{
if (!is_last_elem(e, range)) [[likely]]
os << e << ", ";
else
os << e;
}
os << std::endl;
Full code:
C++20:
#include <iostream>
#include <list>
#include <ranges>
#include <utility>
#include <type_traits>
#include <memory>
template <std::ranges::bidirectional_range R>
bool is_last_elem(const std::ranges::range_value_t<R>& elem, const R& range)
{
auto last_it = range.end();
std::advance(last_it, -1);
return std::addressof(elem) == std::addressof(*last_it);
}
template <std::ranges::bidirectional_range R, class Stream = std::ostream>
void print(const R& range, std::ostream& os = std::cout)
{
for (auto& e : range)
{
if (!is_last_elem(e, range)) [[likely]]
os << e << ", ";
else
os << e;
}
os << std::endl;
}
int main()
{
std::list<int> v{1, 2, 3, 4, 5};
print(v);
}
C++17:
#include <iostream>
#include <list>
#include <utility>
#include <type_traits>
#include <memory>
template <class Range>
using value_type_t = std::remove_reference_t<decltype(*std::begin(std::declval<Range>()))>;
template <class Range>
bool is_last_elem(const value_type_t<Range>& elem, const Range& range)
{
auto last_it = range.end();
std::advance(last_it, -1);
return std::addressof(elem) == std::addressof(*last_it);
}
template <class Range, class Stream = std::ostream>
void print(const Range& range, std::ostream& os = std::cout)
{
for (auto& e : range)
{
if (!is_last_elem(e, range))
os << e << ", ";
else
os << e;
}
os << std::endl;
}
int main()
{
std::list<int> v{1, 2, 3, 4, 5};
print(v);
}
I know how to do this in other languages, but not in C++, which I am forced to use here.
I have a set of strings (keywords) that I'm printing to out as a list, and the strings need a comma between them, but not a trailing comma. In Java, for instance, I would use a StringBuilder and just delete the comma off the end after I've built my string. How can I do it in C++?
auto iter = keywords.begin();
for (iter; iter != keywords.end( ); iter++ )
{
out << *iter << ", ";
}
out << endl;
I initially tried inserting the following block to do it (moving the comma printing here):
if (iter++ != keywords.end())
out << ", ";
iter--;
Use an infix_iterator:
// infix_iterator.h
//
// Lifted from Jerry Coffin's 's prefix_ostream_iterator
#if !defined(INFIX_ITERATOR_H_)
#define INFIX_ITERATOR_H_
#include <ostream>
#include <iterator>
template <class T,
class charT=char,
class traits=std::char_traits<charT> >
class infix_ostream_iterator :
public std::iterator<std::output_iterator_tag,void,void,void,void>
{
std::basic_ostream<charT,traits> *os;
charT const* delimiter;
bool first_elem;
public:
typedef charT char_type;
typedef traits traits_type;
typedef std::basic_ostream<charT,traits> ostream_type;
infix_ostream_iterator(ostream_type& s)
: os(&s),delimiter(0), first_elem(true)
{}
infix_ostream_iterator(ostream_type& s, charT const *d)
: os(&s),delimiter(d), first_elem(true)
{}
infix_ostream_iterator<T,charT,traits>& operator=(T const &item)
{
// Here's the only real change from ostream_iterator:
// Normally, the '*os << item;' would come before the 'if'.
if (!first_elem && delimiter != 0)
*os << delimiter;
*os << item;
first_elem = false;
return *this;
}
infix_ostream_iterator<T,charT,traits> &operator*() {
return *this;
}
infix_ostream_iterator<T,charT,traits> &operator++() {
return *this;
}
infix_ostream_iterator<T,charT,traits> &operator++(int) {
return *this;
}
};
#endif
Usage would be something like:
#include "infix_iterator.h"
// ...
std::copy(keywords.begin(), keywords.end(), infix_iterator(out, ","));
In an experimental C++17 ready compiler coming soon to you, you can use std::experimental::ostream_joiner:
#include <algorithm>
#include <experimental/iterator>
#include <iostream>
#include <iterator>
int main()
{
int i[] = {1, 2, 3, 4, 5};
std::copy(std::begin(i),
std::end(i),
std::experimental::make_ostream_joiner(std::cout, ", "));
}
Live examples using GCC 6.0 SVN and Clang 3.9 SVN
Because everyone has decided to do this with while loops, I'll give an example with for loops.
for (iter = keywords.begin(); iter != keywords.end(); iter++) {
if (iter != keywords.begin()) cout << ", ";
cout << *iter;
}
Assuming a vaguely normal output stream, so that writing an empty string to it does indeed do nothing:
const char *padding = "";
for (auto iter = keywords.begin(); iter != keywords.end(); ++iter) {
out << padding << *iter;
padding = ", "
}
One common approach is to print the first item prior to the loop, and loop only over the remaining items, PRE-printing a comma before each remaining item.
Alternately you should be able to create your own stream that maintains a current state of the line (before endl) and puts commas in the appropriate place.
EDIT:
You can also use a middle-tested loop as suggested by T.E.D. It would be something like:
if(!keywords.empty())
{
auto iter = keywords.begin();
while(true)
{
out << *iter;
++iter;
if(iter == keywords.end())
{
break;
}
else
{
out << ", ";
}
}
}
I mentioned the "print first item before loop" method first because it keeps the loop body really simple, but any of the approaches work fine.
There are lots of clever solutions, and too many that mangle the code beyond hope of salvation without letting the compiler do its job.
The obvious solution, is to special-case the first iteration:
bool first = true;
for (auto const& e: sequence) {
if (first) { first = false; } else { out << ", "; }
out << e;
}
It's a dead simple pattern which:
Does not mangle the loop: it's still obvious at a glance that each element will be iterated on.
Allows more than just putting a separator, or actually printing a list, as the else block and the loop body can contain arbitrary statements.
It may not be the absolutely most efficient code, but the potential performance loss of a single well-predicted branch is very likely to be overshadowed by the massive behemoth that is std::ostream::operator<<.
Something like this?
while (iter != keywords.end())
{
out << *iter;
iter++;
if (iter != keywords.end()) cout << ", ";
}
My typical method for doing separators (in any language) is to use a mid-tested loop. The C++ code would be:
for (;;) {
std::cout << *iter;
if (++iter == keywords.end()) break;
std::cout << ",";
}
(note: An extra if check is needed prior to the loop if keywords may be empty)
Most of the other solutions shown end up doing an entire extra test every loop iteration. You are doing I/O, so the time taken by that isn't a huge problem, but it offends my sensibilities.
In python we just write:
print ", ".join(keywords)
so why not:
template<class S, class V>
std::string
join(const S& sep, const V& v)
{
std::ostringstream oss;
if (!v.empty()) {
typename V::const_iterator it = v.begin();
oss << *it++;
for (typename V::const_iterator e = v.end(); it != e; ++it)
oss << sep << *it;
}
return oss.str();
}
and then just use it like:
cout << join(", ", keywords) << endl;
Unlike in the python example above where the " " is a string and the keywords has to be an iterable of strings, here in this C++ example the separator and keywords can be anything streamable, e.g.
cout << join('\n', keywords) << endl;
I suggest you simply switch the first character with the help of a lambda.
std::function<std::string()> f = [&]() {f = [](){ return ","; }; return ""; };
for (auto &k : keywords)
std::cout << f() << k;
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;
}
}
to avoid placing an if inside the loop, I use this:
vector<int> keywords = {1, 2, 3, 4, 5};
if (!keywords.empty())
{
copy(keywords.begin(), std::prev(keywords.end()),
std::ostream_iterator<int> (std::cout,", "));
std::cout << keywords.back();
}
It depends on the vector type, int, but you can remove it with some helper.
If the values are std::strings 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;
}
There is a little problem with the ++ operator you are using.
You can try:
if (++iter != keywords.end())
out << ", ";
iter--;
This way, ++ will be evaluated before compare the iterator with keywords.end().
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;
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.
Following should do:-
const std::vector<__int64>& a_setRequestId
std::stringstream strStream;
std::copy(a_setRequestId.begin(), a_setRequestId.end() -1, std::ostream_iterator<__int64>(strStream, ", "));
strStream << a_setRequestId.back();
I think this variant of #MarkB's answer strikes optimal balance of readability, simplicity and terseness:
auto iter= keywords.begin();
if (iter!=keywords.end()) {
out << *iter;
while(++iter != keywords.end())
out << "," << *iter;
}
out << endl;
It's very easy to fix that (taken from my answer here):
bool print_delim = false;
for (auto iter = keywords.begin(); iter != keywords.end( ); iter++ ) {
if(print_delim) {
out << ", ";
}
out << *iter;
print_delim = true;
}
out << endl;
I am using this idiom (pattern?) in many programming languages, and all kind of tasks where you need to construct delimited output from list like inputs. Let me give the abstract in pseudo code:
empty output
firstIteration = true
foreach item in list
if firstIteration
add delimiter to output
add item to output
firstIteration = false
In some cases one could even omit the firstIteration indicator variable completely:
empty output
foreach item in list
if not is_empty(output)
add delimiter to output
add item to output
I think simplicity is better for me, so after I look through all answers I prepared my solution(c++14 required):
#include <iostream>
#include <vector>
#include <utility> // for std::exchange c++14
int main()
{
std::vector nums{1, 2, 3, 4, 5}; // c++17
const char* delim = "";
for (const auto value : nums)
{
std::cout << std::exchange(delim, ", ") << value;
}
}
Output example:
1, 2, 3, 4, 5
I think this should work
while (iter != keywords.end( ))
{
out << *iter;
iter++ ;
if (iter != keywords.end( )) out << ", ";
}
Using boost:
std::string add_str("");
const std::string sep(",");
for_each(v.begin(), v.end(), add_str += boost::lambda::ret<std::string>(boost::lambda::_1 + sep));
and you obtain a string containing the vector, comma delimited.
EDIT:
to remove the last comma, just issue:
add_str = add_str.substr(0, add_str.size()-1);
Could be like so..
bool bFirst = true;
for (auto curr = keywords.begin(); curr != keywords.end(); ++curr) {
std::cout << (bFirst ? "" : ", ") << *curr;
bFirst = false;
}
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.
Method 1: 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.
Method 2: the print last method
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";
}
I would go with something like this, an easy solution and should work for all iterators.
int maxele = maxele = v.size() - 1;
for ( cur = v.begin() , i = 0; i < maxele ; ++i)
{
std::cout << *cur++ << " , ";
}
if ( maxele >= 0 )
{
std::cout << *cur << std::endl;
}
You can use a do loop, rewrite the loop condition for the first iteration, and use the short-circuit && operator and the fact that a valid stream is true.
auto iter = keywords.begin();
if ( ! keywords.empty() ) do {
out << * iter;
} while ( ++ iter != keywords.end() && out << ", " );
out << endl;
This one overloads the stream operator. Yes global variables are evil.
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
int index = 0;
template<typename T, template <typename, typename> class Cont>
std::ostream& operator<<(std::ostream& os, const Cont<T, std::allocator<T>>& vec)
{
if (index < vec.size()) {
if (index + 1 < vec.size())
return os << vec[index++] << "-" << vec;
else
return os << vec[index++] << vec;
} else return os;
}
int main()
{
std::vector<int> nums(10);
int n{0};
std::generate(nums.begin(), nums.end(), [&]{ return n++; });
std::cout << nums << std::endl;
}
Can use functors:
#include <functional>
string getSeparatedValues(function<bool()> condition, function<string()> output, string separator)
{
string out;
out += output();
while (condition())
out += separator + output();
return out;
}
Example:
if (!keywords.empty())
{
auto iter = keywords.begin();
cout << getSeparatedValues([&]() { return ++iter != keywords.end(); }, [&]() { return *iter; }, ", ") << endl;
}
A combination of c++11 lambda and macro:
#define INFIX_PRINTER(os, sep)([&]()->decltype(os)&{static int f=1;os<<(f?(f=0,""):sep);return os;})()
Usage:
for(const auto& k: keywords)
INFIX_PRINTER(out, ", ") << k;
I like a range-based for with a is_last_elem test. That imho it's very readable:
for (auto& e : range)
{
if (!is_last_elem(e, range)) [[likely]]
os << e << ", ";
else
os << e;
}
os << std::endl;
Full code:
C++20:
#include <iostream>
#include <list>
#include <ranges>
#include <utility>
#include <type_traits>
#include <memory>
template <std::ranges::bidirectional_range R>
bool is_last_elem(const std::ranges::range_value_t<R>& elem, const R& range)
{
auto last_it = range.end();
std::advance(last_it, -1);
return std::addressof(elem) == std::addressof(*last_it);
}
template <std::ranges::bidirectional_range R, class Stream = std::ostream>
void print(const R& range, std::ostream& os = std::cout)
{
for (auto& e : range)
{
if (!is_last_elem(e, range)) [[likely]]
os << e << ", ";
else
os << e;
}
os << std::endl;
}
int main()
{
std::list<int> v{1, 2, 3, 4, 5};
print(v);
}
C++17:
#include <iostream>
#include <list>
#include <utility>
#include <type_traits>
#include <memory>
template <class Range>
using value_type_t = std::remove_reference_t<decltype(*std::begin(std::declval<Range>()))>;
template <class Range>
bool is_last_elem(const value_type_t<Range>& elem, const Range& range)
{
auto last_it = range.end();
std::advance(last_it, -1);
return std::addressof(elem) == std::addressof(*last_it);
}
template <class Range, class Stream = std::ostream>
void print(const Range& range, std::ostream& os = std::cout)
{
for (auto& e : range)
{
if (!is_last_elem(e, range))
os << e << ", ";
else
os << e;
}
os << std::endl;
}
int main()
{
std::list<int> v{1, 2, 3, 4, 5};
print(v);
}
I have a file which contains the following lines,
connection list
current check OK
connect "A" to "B"
connect "A" to "C"
connect "A" to "D"
connect "C" to "A"
connect "A" to "E"
Here connect "C" to "A" is a reverse connection to connect "A" to "C"
The requirement is to remove the duplicate reverse connection.
I am new to C++ and vector. I tried using the following:
First I took a structure of 2 strings con1 and con2: connectPair
Then I took a vector of the structure
Now, I am saving the file lines to a vector: rawFileLines
I am trying to operate on rawFileLines to find the connection components.
I am storing the connection components to another vector: values
Here is my code:
typedef struct {
std::string con1;
std::string con2;
} ConnectPair;
void RemoveReversePairs(std::string inputFile) {
std::vector<std::string> fileData;
std::string line, scan, token1, token2;
std::size_t tokenLeft, tokenRight, maxLines, lineNumber = 0, pos = 0;
std::size_t found = 0, storeCount = 0;
std::vector<std::string> rawFileLines;
ConnectPair connectPair = {};
std::vector<ConnectPair> values;
std::ifstream source(inputFile.c_str());
while (std::getline(source, line)) {
rawFileLines.push_back(line);
}
source.close();
maxLines = rawFileLines.size();
for (size_t i = 0; i < maxLines; i++) {
line = rawFileLines[i];
pos = 0;
scan = "\"";
found = 0;
while (found < 2) /*line.find(scan, pos) != std::string::npos*/ {
tokenLeft = line.find(scan, pos);
tokenRight = line.find(scan, tokenLeft + 1);
if ((tokenLeft != std::string::npos) && (tokenRight != std::string::npos)) {
found++;
if (found == 1) {
connectPair.con1 = line.substr(tokenLeft + 1, (tokenRight - tokenLeft) - 1);
}
else if (found == 2) {
connectPair.con2 = line.substr(tokenLeft + 1, (tokenRight - tokenLeft) - 1);
values.push_back(connectPair);
storeCount++;
}
pos = tokenRight + 1;
}
else {
connectPair.con1 = "++";
connectPair.con2 = "++";
values.push_back(connectPair);
fileData.push_back(line);
break;
}
}
}
Now, I am having trouble comparing the connections. Please suggest me how to proceed.
Thank you.
Leaving the code to read in the connections to you as you mentioned in comments that that was working for you, consider an STL solution using the algorithms header's find_if along with a lambda.
For simplicity I have a std::vector<std::pair<std::string, std::string>> populated with your sample connections data.
I use a loop to print it to ensure the data is what I expect. This loop makes use of destructuring to cut out a lot of annoying boilerplate.
Then comes the real meat of the solution. We use an explicit iterator to loop over the vector, using std::find_if to check the rest of the vector for connections that are either identical, or are identical when reversed. If std::find_if returns the end iterator, it didn't find anything, and we can push that pair back onto the map2 vector. If an equivalent does exist in the rest of the vector, the current pair does not get pushed onto the map2 vector.
In the lambda it's important that we capture the current iter so we can compare it to the rest of them (represented by the argument to the lambda b).
[&iter](auto b) {
return (iter->first == b.first && iter->second == b.second) ||
(iter->first == b.second && iter->second == b.first );
}
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
int main() {
std::vector<std::pair<std::string, std::string>> map, map2;
map.push_back({"A", "B"});
map.push_back({"A", "C"});
map.push_back({"A", "D"});
map.push_back({"C", "A"});
map.push_back({"A", "E"});
std::cout << "Before:" << std::endl;
for (auto &[k, v] : map) {
std::cout << k << " -> " << v << std::endl;
}
auto end = map.end();
for (auto iter = map.begin(); iter != end; iter++) {
if (std::find_if(iter + 1, end,
[&iter](auto b) {
return (iter->first == b.first && iter->second == b.second) ||
(iter->first == b.second && iter->second == b.first );
}) == end) {
map2.push_back(*iter);
}
}
std::cout << "After: " << std::endl;
for (auto &[k, v] : map2) {
std::cout << k << " -> " << v << std::endl;
}
}
Result:
Before:
A -> B
A -> C
A -> D
C -> A
A -> E
After:
A -> B
A -> D
C -> A
A -> E
Better yet
After considering my previous example, I realized it can be simpler if we use the same comparison logic (the lambda is unchanged) to check if each connection already exists in map2.
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
int main() {
std::vector<std::pair<std::string, std::string>> map, map2;
map.push_back({"A", "B"});
map.push_back({"A", "C"});
map.push_back({"A", "D"});
map.push_back({"C", "A"});
map.push_back({"A", "E"});
std::cout << "Before:" << std::endl;
for (auto &[k, v] : map) {
std::cout << k << " -> " << v << std::endl;
}
auto end = map.end();
for (auto iter = map.begin(); iter != end; iter++) {
if (std::find_if(map2.begin(), map2.end(),
[&iter](auto b) {
return (iter->first == b.first && iter->second == b.second) ||
(iter->first == b.second && iter->second == b.first );
}) == map2.end()) {
map2.push_back(*iter);
}
}
std::cout << "After: " << std::endl;
for (auto &[k, v] : map2) {
std::cout << k << " -> " << v << std::endl;
}
}
The other benefit of this is that we now get the first of the "duplicates" in map2 rather than the last.
Before:
A -> B
A -> C
A -> D
C -> A
A -> E
After:
A -> B
A -> C
A -> D
A -> E
Let me first say that I think that your code is somehow complicated.
Then, next. To remove the duplicates you can use the erase / remove_if idiom.
The code fragment that you need to put at the end of your function could be:
int i = 1;
while (i < values.size()) {
values.erase(std::remove_if(values.begin(), values.end(),
[&](const ConnectPair& cp)-> bool
{ return ((cp.con1 == values[i].con1) && (cp.con2 == values[i].con2)) || ((cp.con1 == values[i].con2) && (cp.con2 == values[i].con1)); }),
values.end());
++i;
}
Important is here the compare function. You make a 1 to 1 comparison and additionally you compare con1 with con2 and vice versa.
But let me say. Life can be easier. You can add alreadya compare function to your struct. That would be the more object oriented approach. And then you can use your struct in an appropriate container like std::set which will not allow duplicates.
And because we will not use a direction, but a connection, we can simply sort the first and the second element. This makes comparison ultra simple.
And the whole reading of data and doing all the task, can the be done in one line of code in main.
Please see:
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <regex>
#include <utility>
#include <set>
const std::regex re{ R"(\"(\w+)\")" };
struct Terminal {
// Store undirected connection in a noram std::pair
std::pair<std::string, std::string> end{};
// Read new connection from stream
friend std::istream& operator >> (std::istream& is, Terminal& t) {
bool found{};
// Read a line, until we found a connection or until eof
for (std::string line{}; not found and std::getline(is, line);)
// Get connection end names
if (std::vector ends(std::sregex_token_iterator(line.begin(), line.end(), re), {}); found = (ends.size() == 2))
t.end = std::minmax(ends[0], ends[1]);
return is;
}
bool operator < (const Terminal& other) const { return end < other.end; }
};
int main() {
// Open file and check, if it could be opened
if (std::ifstream inputFileStream{ "r:\\data.txt" }; inputFileStream) {
// Read complete data, without doubles into our container
std::set data(std::istream_iterator<Terminal>(inputFileStream), {});
// Debug output
for (const auto& d : data) std::cout << d.end.first << " <-> " << d.end.second << '\n';
}
}
Please note, if you need to original data, then one line with the original pair can be added to the struct.
Since your connection is unidirectional implicitly.
I'll suggest to use std::unordered_map<std::string,set::unordered_set<std::string>> if data has tons of connections to handle.
Because both unordered_map and unordered_set has constant time to lookup on average, but it takes longer time to insert.
I borrowed Chris's code to construct data.
Please note that Chris's example is good enough if your data is not large.
Live demo
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <map>
#include <unordered_set>
int main() {
std::vector<std::pair<std::string, std::string>> map;
map.push_back({"A", "B"});
map.push_back({"A", "C"});
map.push_back({"A", "D"});
map.push_back({"D", "A"});
map.push_back({"C", "A"});
map.push_back({"A", "E"});
map.push_back({"E", "A"});
std::cout << "Before:" << std::endl;
for (auto &[k, v] : map) {
std::cout << k << " -> " << v << std::endl;
}
std::unordered_map<std::string,std::unordered_set<std::string>> connection;
for (auto &[k, v] : map) {
// Existed connection
if((connection[k].find(v) != connection[k].end()) || (connection[v].find(k) != connection[v].end()) ){
continue;
}
connection[k].insert(v);
}
std::cout << "After: " << std::endl;
for (auto &[k, v] : connection) {
for(auto& item : v){
std::cout << k << " -> " << item << std::endl;
}
}
}
I know how to do this in other languages, but not in C++, which I am forced to use here.
I have a set of strings (keywords) that I'm printing to out as a list, and the strings need a comma between them, but not a trailing comma. In Java, for instance, I would use a StringBuilder and just delete the comma off the end after I've built my string. How can I do it in C++?
auto iter = keywords.begin();
for (iter; iter != keywords.end( ); iter++ )
{
out << *iter << ", ";
}
out << endl;
I initially tried inserting the following block to do it (moving the comma printing here):
if (iter++ != keywords.end())
out << ", ";
iter--;
Use an infix_iterator:
// infix_iterator.h
//
// Lifted from Jerry Coffin's 's prefix_ostream_iterator
#if !defined(INFIX_ITERATOR_H_)
#define INFIX_ITERATOR_H_
#include <ostream>
#include <iterator>
template <class T,
class charT=char,
class traits=std::char_traits<charT> >
class infix_ostream_iterator :
public std::iterator<std::output_iterator_tag,void,void,void,void>
{
std::basic_ostream<charT,traits> *os;
charT const* delimiter;
bool first_elem;
public:
typedef charT char_type;
typedef traits traits_type;
typedef std::basic_ostream<charT,traits> ostream_type;
infix_ostream_iterator(ostream_type& s)
: os(&s),delimiter(0), first_elem(true)
{}
infix_ostream_iterator(ostream_type& s, charT const *d)
: os(&s),delimiter(d), first_elem(true)
{}
infix_ostream_iterator<T,charT,traits>& operator=(T const &item)
{
// Here's the only real change from ostream_iterator:
// Normally, the '*os << item;' would come before the 'if'.
if (!first_elem && delimiter != 0)
*os << delimiter;
*os << item;
first_elem = false;
return *this;
}
infix_ostream_iterator<T,charT,traits> &operator*() {
return *this;
}
infix_ostream_iterator<T,charT,traits> &operator++() {
return *this;
}
infix_ostream_iterator<T,charT,traits> &operator++(int) {
return *this;
}
};
#endif
Usage would be something like:
#include "infix_iterator.h"
// ...
std::copy(keywords.begin(), keywords.end(), infix_iterator(out, ","));
In an experimental C++17 ready compiler coming soon to you, you can use std::experimental::ostream_joiner:
#include <algorithm>
#include <experimental/iterator>
#include <iostream>
#include <iterator>
int main()
{
int i[] = {1, 2, 3, 4, 5};
std::copy(std::begin(i),
std::end(i),
std::experimental::make_ostream_joiner(std::cout, ", "));
}
Live examples using GCC 6.0 SVN and Clang 3.9 SVN
Because everyone has decided to do this with while loops, I'll give an example with for loops.
for (iter = keywords.begin(); iter != keywords.end(); iter++) {
if (iter != keywords.begin()) cout << ", ";
cout << *iter;
}
Assuming a vaguely normal output stream, so that writing an empty string to it does indeed do nothing:
const char *padding = "";
for (auto iter = keywords.begin(); iter != keywords.end(); ++iter) {
out << padding << *iter;
padding = ", "
}
One common approach is to print the first item prior to the loop, and loop only over the remaining items, PRE-printing a comma before each remaining item.
Alternately you should be able to create your own stream that maintains a current state of the line (before endl) and puts commas in the appropriate place.
EDIT:
You can also use a middle-tested loop as suggested by T.E.D. It would be something like:
if(!keywords.empty())
{
auto iter = keywords.begin();
while(true)
{
out << *iter;
++iter;
if(iter == keywords.end())
{
break;
}
else
{
out << ", ";
}
}
}
I mentioned the "print first item before loop" method first because it keeps the loop body really simple, but any of the approaches work fine.
There are lots of clever solutions, and too many that mangle the code beyond hope of salvation without letting the compiler do its job.
The obvious solution, is to special-case the first iteration:
bool first = true;
for (auto const& e: sequence) {
if (first) { first = false; } else { out << ", "; }
out << e;
}
It's a dead simple pattern which:
Does not mangle the loop: it's still obvious at a glance that each element will be iterated on.
Allows more than just putting a separator, or actually printing a list, as the else block and the loop body can contain arbitrary statements.
It may not be the absolutely most efficient code, but the potential performance loss of a single well-predicted branch is very likely to be overshadowed by the massive behemoth that is std::ostream::operator<<.
Something like this?
while (iter != keywords.end())
{
out << *iter;
iter++;
if (iter != keywords.end()) cout << ", ";
}
My typical method for doing separators (in any language) is to use a mid-tested loop. The C++ code would be:
for (;;) {
std::cout << *iter;
if (++iter == keywords.end()) break;
std::cout << ",";
}
(note: An extra if check is needed prior to the loop if keywords may be empty)
Most of the other solutions shown end up doing an entire extra test every loop iteration. You are doing I/O, so the time taken by that isn't a huge problem, but it offends my sensibilities.
In python we just write:
print ", ".join(keywords)
so why not:
template<class S, class V>
std::string
join(const S& sep, const V& v)
{
std::ostringstream oss;
if (!v.empty()) {
typename V::const_iterator it = v.begin();
oss << *it++;
for (typename V::const_iterator e = v.end(); it != e; ++it)
oss << sep << *it;
}
return oss.str();
}
and then just use it like:
cout << join(", ", keywords) << endl;
Unlike in the python example above where the " " is a string and the keywords has to be an iterable of strings, here in this C++ example the separator and keywords can be anything streamable, e.g.
cout << join('\n', keywords) << endl;
I suggest you simply switch the first character with the help of a lambda.
std::function<std::string()> f = [&]() {f = [](){ return ","; }; return ""; };
for (auto &k : keywords)
std::cout << f() << k;
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;
}
}
to avoid placing an if inside the loop, I use this:
vector<int> keywords = {1, 2, 3, 4, 5};
if (!keywords.empty())
{
copy(keywords.begin(), std::prev(keywords.end()),
std::ostream_iterator<int> (std::cout,", "));
std::cout << keywords.back();
}
It depends on the vector type, int, but you can remove it with some helper.
If the values are std::strings 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;
}
There is a little problem with the ++ operator you are using.
You can try:
if (++iter != keywords.end())
out << ", ";
iter--;
This way, ++ will be evaluated before compare the iterator with keywords.end().
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;
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.
Following should do:-
const std::vector<__int64>& a_setRequestId
std::stringstream strStream;
std::copy(a_setRequestId.begin(), a_setRequestId.end() -1, std::ostream_iterator<__int64>(strStream, ", "));
strStream << a_setRequestId.back();
I think this variant of #MarkB's answer strikes optimal balance of readability, simplicity and terseness:
auto iter= keywords.begin();
if (iter!=keywords.end()) {
out << *iter;
while(++iter != keywords.end())
out << "," << *iter;
}
out << endl;
It's very easy to fix that (taken from my answer here):
bool print_delim = false;
for (auto iter = keywords.begin(); iter != keywords.end( ); iter++ ) {
if(print_delim) {
out << ", ";
}
out << *iter;
print_delim = true;
}
out << endl;
I am using this idiom (pattern?) in many programming languages, and all kind of tasks where you need to construct delimited output from list like inputs. Let me give the abstract in pseudo code:
empty output
firstIteration = true
foreach item in list
if firstIteration
add delimiter to output
add item to output
firstIteration = false
In some cases one could even omit the firstIteration indicator variable completely:
empty output
foreach item in list
if not is_empty(output)
add delimiter to output
add item to output
I think simplicity is better for me, so after I look through all answers I prepared my solution(c++14 required):
#include <iostream>
#include <vector>
#include <utility> // for std::exchange c++14
int main()
{
std::vector nums{1, 2, 3, 4, 5}; // c++17
const char* delim = "";
for (const auto value : nums)
{
std::cout << std::exchange(delim, ", ") << value;
}
}
Output example:
1, 2, 3, 4, 5
I think this should work
while (iter != keywords.end( ))
{
out << *iter;
iter++ ;
if (iter != keywords.end( )) out << ", ";
}
Using boost:
std::string add_str("");
const std::string sep(",");
for_each(v.begin(), v.end(), add_str += boost::lambda::ret<std::string>(boost::lambda::_1 + sep));
and you obtain a string containing the vector, comma delimited.
EDIT:
to remove the last comma, just issue:
add_str = add_str.substr(0, add_str.size()-1);
Could be like so..
bool bFirst = true;
for (auto curr = keywords.begin(); curr != keywords.end(); ++curr) {
std::cout << (bFirst ? "" : ", ") << *curr;
bFirst = false;
}
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.
Method 1: 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.
Method 2: the print last method
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";
}
I would go with something like this, an easy solution and should work for all iterators.
int maxele = maxele = v.size() - 1;
for ( cur = v.begin() , i = 0; i < maxele ; ++i)
{
std::cout << *cur++ << " , ";
}
if ( maxele >= 0 )
{
std::cout << *cur << std::endl;
}
You can use a do loop, rewrite the loop condition for the first iteration, and use the short-circuit && operator and the fact that a valid stream is true.
auto iter = keywords.begin();
if ( ! keywords.empty() ) do {
out << * iter;
} while ( ++ iter != keywords.end() && out << ", " );
out << endl;
This one overloads the stream operator. Yes global variables are evil.
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
int index = 0;
template<typename T, template <typename, typename> class Cont>
std::ostream& operator<<(std::ostream& os, const Cont<T, std::allocator<T>>& vec)
{
if (index < vec.size()) {
if (index + 1 < vec.size())
return os << vec[index++] << "-" << vec;
else
return os << vec[index++] << vec;
} else return os;
}
int main()
{
std::vector<int> nums(10);
int n{0};
std::generate(nums.begin(), nums.end(), [&]{ return n++; });
std::cout << nums << std::endl;
}
Can use functors:
#include <functional>
string getSeparatedValues(function<bool()> condition, function<string()> output, string separator)
{
string out;
out += output();
while (condition())
out += separator + output();
return out;
}
Example:
if (!keywords.empty())
{
auto iter = keywords.begin();
cout << getSeparatedValues([&]() { return ++iter != keywords.end(); }, [&]() { return *iter; }, ", ") << endl;
}
A combination of c++11 lambda and macro:
#define INFIX_PRINTER(os, sep)([&]()->decltype(os)&{static int f=1;os<<(f?(f=0,""):sep);return os;})()
Usage:
for(const auto& k: keywords)
INFIX_PRINTER(out, ", ") << k;
I like a range-based for with a is_last_elem test. That imho it's very readable:
for (auto& e : range)
{
if (!is_last_elem(e, range)) [[likely]]
os << e << ", ";
else
os << e;
}
os << std::endl;
Full code:
C++20:
#include <iostream>
#include <list>
#include <ranges>
#include <utility>
#include <type_traits>
#include <memory>
template <std::ranges::bidirectional_range R>
bool is_last_elem(const std::ranges::range_value_t<R>& elem, const R& range)
{
auto last_it = range.end();
std::advance(last_it, -1);
return std::addressof(elem) == std::addressof(*last_it);
}
template <std::ranges::bidirectional_range R, class Stream = std::ostream>
void print(const R& range, std::ostream& os = std::cout)
{
for (auto& e : range)
{
if (!is_last_elem(e, range)) [[likely]]
os << e << ", ";
else
os << e;
}
os << std::endl;
}
int main()
{
std::list<int> v{1, 2, 3, 4, 5};
print(v);
}
C++17:
#include <iostream>
#include <list>
#include <utility>
#include <type_traits>
#include <memory>
template <class Range>
using value_type_t = std::remove_reference_t<decltype(*std::begin(std::declval<Range>()))>;
template <class Range>
bool is_last_elem(const value_type_t<Range>& elem, const Range& range)
{
auto last_it = range.end();
std::advance(last_it, -1);
return std::addressof(elem) == std::addressof(*last_it);
}
template <class Range, class Stream = std::ostream>
void print(const Range& range, std::ostream& os = std::cout)
{
for (auto& e : range)
{
if (!is_last_elem(e, range))
os << e << ", ";
else
os << e;
}
os << std::endl;
}
int main()
{
std::list<int> v{1, 2, 3, 4, 5};
print(v);
}
vector<string> v;
v.push_back("A");
v.push_back("B");
v.push_back("C");
v.push_back("D");
for (vector<int>::iterator it = v.begin(); it!=v.end(); ++it) {
//printout
cout << *it << endl;
}
I like to add a comma after each element as follow:
A,B,C,D
I tried researching on Google, but I only found CSV to vector.
Loop way:
for (vector<string>::iterator it = v.begin(); it != v.end(); ++it) {
if (it != v.begin()) cout << ',';
cout << *it;
}
"Clever" way:
#include <algorithm>
#include <iterator>
if (v.size() >= 2)
copy(v.begin(), v.end()-1, ostream_iterator<string>(cout, ","));
if (v.size() >= 1)
cout << v.back();
With a normal ostream_iterator, you'll get a comma after every data item -- including the last, where you don't want one.
I posted an infix_iterator in a previous answer that fixes this problem, only putting commas between the data items, not after the final one.
Below should do the job. Thanks.
ofstream CSVToFile("ava.csv", ios::out | ios::binary);
//////////////////vector element to CSV////////////////////////////////////////
for (std::vector<string>::iterator i = ParamHeaders.begin(); i != ParamHeaders.end(); i++)
{
if (i != ParamHeaders.begin())
{
CSVToFile << ",";
std::cout << ",";
}
std::cout << *i;
CSVToFile << *i;
}
This is an old question but I noticed that a couple of people used two explicit tests to stop the last comma from appearing. That's unnecessary. Only need to test if the vector is not empty. If the vector contains one element then the copy becomes a no-op.
std::vector<std::string> V { "A", "B", "C", "D" };
if (!V.empty()) {
std::copy(V.begin(), V.end() - 1, std::ostream_iterator<std::string>(std::cout, ", "));
std::cout << V.back();
}
If you want a function that takes begin and end args:
template<typename OS, typename IT>
OS& csv(OS& os, IT begin, IT end, char const* delim = ", ") {
if (begin != end) {
using value_type = typename std::iterator_traits<IT>::value_type;
std::copy(begin, end - 1, std::ostream_iterator<value_type>(os, delim));
os << end[-1];
}
return os;
}
Does really nobody know the std::experimental::ostream_joiner?. See here. To be used in algorithms, like std::copy
Or, if you do not want to use std::experimental alternatively, std::exchange? See here
Like this:
#include <iostream>
#include <vector>
#include <utility>
int main() {
std::vector data{1,2,3,4};
bool showComma{};
for (const int i: data) std::cout << (std::exchange(showComma, true) ? "," : "") << i;
}
Maybe, I have a misunderstanding . . .
To avoid the trailing comma, loop until v.end() - 1, and output v.back() for instance:
#include <vector>
#include <iostream>
#include <iterator>
#include <string>
#include <iostream>
template <class Val>
void Out(const std::vector<Val>& v)
{
if (v.size() > 1)
std::copy(v.begin(), v.end() - 1, std::ostream_iterator<Val>(std::cout, ", "));
if (v.size())
std::cout << v.back() << std::endl;
}
int main()
{
const char* strings[] = {"A", "B", "C", "D"};
Out(std::vector<std::string>(strings, strings + sizeof(strings) / sizeof(const char*)));
const int ints[] = {1, 2, 3, 4};
Out(std::vector<int>(ints, ints + sizeof(ints) / sizeof(int)));
}
BTW you posted:
vector<string> v;
//...
for (vector<int>::iterator it = v.begin(); //...
which is unlikely to compile :)