Checking if current element is last element of set - c++

I am trying to write a print function for set in C++, and this is what I wrote :
void print_set(set<int> &s)
{
cout<<"{";
for(auto it = s.begin() ; it!=s.end() ; ++it)
{
cout<<*it;
if(it!=(s.end()-1)) //shows error here
cout<<",";
}
cout<<"}";
}
But I am getting error. How can I check whether current element is last element or not ?

set's integers are not random-access, so you can't do arithmetic on them. Use std::prev instead.

May I suggest an alternative approach?
Print the comma before each element, except the first:
void print_set(set<int> &s)
{
cout << "{";
for(auto it = s.begin() ; it != s.end() ; ++it)
{
if(it != s.begin())
cout << ", ";
cout << *it;
}
cout << "}";
}

Simply check whether the next element equals the end:
auto next = it;
++next;
if (next != s.end())
cout << ",";

You can only apply the ++ and -- operators on set iterators. Adding a number is not defined. You can make your code work like so:
void print_set(set<int> &s)
{
cout<<"{";
auto second_to_last = s.end();
if (!s.empty()) {
second_to_last--;
}
for(auto it = s.begin() ; it!=s.end() ; ++it)
{
cout<<*it;
if(it!=second_to_last) {
cout<<", ";
}
}
cout<<"}";
}
What this code does is essentially store an iterator to the second to last element once and then compare the element you have with it. Please note that second_to_last will not be accurate if the set is empty but the code will still work as expected.

What I do in this case:
void print_set(const std::set<int>& s)
{
const char* sep = "";
std::cout << "{";
for (int e : s)
{
std::cout << sep << e;
sep = ", ";
}
std::cout << "}";
}

Related

C++ Use the methods of vector with a struct

i would like to do a thing like this. can ou help me :) Thank you
/* Example: */
struct Name
{
const char *full_name;
const char *name;
};
std::vector<Name> n = { {"Harry Potter", "Harry"}, {"Hermione Granger", "Hermione"} };
// The expressions below does not work
string::const_iterator b = n.begin();
string::const_iterator e = n.end();
int s = n.size();
// ...
The problem mainly comes from the :
string::const_iterator b = n.begin(); // not possible
string::const_iterator e = n.end(); // not possible
int s = n.size(); // working as intended if you print it to the console
If you want to declare an iterator, in this case, you could do :
std::vector<Name>::const_iterator it;
If you would like to have control with the iterator, use it in a for loop :
for (it = n.begin(); it != n.end() - 1; it++) // Will stop at the first name in our example
{
std::cout << it->full_name << std::endl;
}
As it is pointing to n, in order to access its values, don't forget to use ->.
If you wanted to iterate through the whole vector, it is possible to use a simple loop.`
for (auto i: n)
{
std::cout << "My name is " << i.name << ", ";
std::cout << i.full_name << std::endl;
}`
On a side note, you did not need to declare "it" before it was used in the for loop.
The following would work too :
for (auto it = n.begin(); it != n.end() - 1; it++) // Will stop at the first name in our example
{
std::cout << it->full_name << std::endl;
}
For reference, here is my final code with examples, I hope that solves your problem :
struct Name
{
std::string full_name;
std::string name;
};
int main()
{
std::vector<Name> n = { {"Harry Potter", "Harry"}, {"Hermione Granger", "Hermione"} };
std::vector<Name>::const_iterator it;
for (auto i : n) // Printing the whole vector
{
std::cout << "My name is " << i.name << ", ";
std::cout << i.full_name << std::endl;
}
for (it = n.begin(); it != n.end() - 1; it++) // will return all the names except the last
{
std::cout << it->full_name << std::endl;
}
for (auto g = n.begin(); g != n.end() - 1; g++) // same as it, iterator initialized in the loop
{
std::cout << g->full_name << std::endl;
}
return 0;
}

Printing a list of lists C++ STL list

I have a top list that stores inner lists. I'm using the standard template library list template.
I am attempting to print the values of the inner lists.
The top list is "L" and the inner list is "I".
void ListofLists::dump()
{
list<list<IntObj>>::iterator itr;
for (itr = L.begin(); itr != L.end(); itr++)
{
list<IntObj>::iterator it;
for (it = I.begin(); it != I.end(); it++)
{
cout << *it << " ";
}
cout << endl << "End" << endl;
}
}
My IDE doesn't like the line cout << *it << " ";and I'm not really sure how to change it while having the program do what I want it to do, which is print the data inside of the lists.
It red underlined the “<<“ operator and says “no operator “<<“ matches these operands.”
Can someone help me as to why? I've looked and can't really find what I'm looking for. I'm not understanding something correctly. I know it is adding the data to the data structure correctly because my IDE enables me to view my locals.
Thanks to anyone who helps! Means a lot.
Try to use :
list<IntObj>::const_iterator i;
instead the one you are using to avoid compiling error.
The inner loop does not make sense.
If you want to use iterators then the function can be defined like
void ListofLists::dump() /* const */
{
for (list<list<IntObj>>::iterator itr = L.begin(); itr != L.end(); itr++)
{
for ( list<IntObj>::iterator it = itr->begin(); it != itr->end(); it++)
{
cout << *it << " ";
}
cout << endl << "End" << endl;
}
}
However it will be simpler to use the range-based for loop. For example
void ListofLists::dump() /* const */
{
for ( const auto &inner_list : L )
{
for ( const auto &item : inner_list )
{
cout << item << " ";
}
cout << endl << "End" << endl;
}
}
Take into account that you have to define the operator << for the class IntObj.
Its declaration should look like
std::ostream & operator <<( std::ostream &, const IntObj & );

C++ printing a list of sets

I'm trying to print out a list of sets but I'm confused with the syntax. I want each set to be on a new line. Here is my code:
set<int> set1 = { 2, 4, 5 };
set<int> set2 = { 4, 5 };
list<set<int>> list1;
list<set<int>>::iterator it = list1.begin();
list1.insert(it, set1);
list1.insert(it, set2);
cout << "List contents:" << endl;
for (it = list1.begin(); it != list1.end(); ++it)
{
cout << *it; //error is here
}
I'm getting an error when trying to print the pointer to the iterator. Pretty sure its because I'm using a set inside of the list, but I don't know the proper syntax for outputting this list.
Do you want to print as following?
for (it = list1.begin(); it != list1.end(); ++it)
{
for (set<int>::iterator s = it->begin(); s != it->end(); s++) {
cout << *s << ' ';
}
cout << endl;
}
output:
List contents:
2 4 5
4 5
There is no overload of operator << for std::set, you have to write the loop yourself (and possibly creating a function for that)
With for range, you may simply do:
for (const auto& s : list1) {
for (int i : s) {
std::cout << i << ' ';
}
std::cout << std::endl;
}

How can I get the current position without another variable?

Many times when creating a grammatical list (with comas), I use similar code to the following:
std::stringstream list;
int i = 0;
for (auto itemListIt = itemList.begin(); itemListIt != itemList.end(); itemListIt++)
{
list << *itemListIt;
if (i < itemList.size() - 1) list << ", ";
i++;
}
Is there some more concise way do this, perhaps without the extra variable - 'i'?
Why not test what you're really interested in; "Is there another element after this one?".
std::stringstream list;
for (auto it = roomList.begin(); it != itemList.end(); it++)
{
list << *it;
if ( it+1 != itemList.end() ) list << ", ";
}
There are two simple solutions for this. The first is to use a while
loop:
auto itemListIt = itemList.begin();
while ( itemListIt != itemList.end() ) {
list << *itemListIt;
++ itemListIt;
if ( itemListIt != itemList.end() ) {
list << ", ";
}
}
The second solution is to change the logic slightly: instead of
appending a ", " if there is more to follow, prefix one if you're not
the first element:
for ( auto itemListIt = itemList.begin(); itemListIt != itemList.end(); ++ itemListIt ) {
if ( itemListIt != itemList.begin() ) {
list << ", ";
}
list << *itemListIt;
}
You can loop over everything up to the next to last using --items.end().
Then output the last one using items.back().
#include <algorithm>
#include <iterator>
#include <sstream>
#include <vector>
#include <iostream>
int main()
{
std::ostringstream oss;
std::vector<int> items;
items.push_back(1);
items.push_back(1);
items.push_back(2);
items.push_back(3);
items.push_back(5);
items.push_back(8);
if(items.size() > 1)
{
std::copy(items.begin(), --items.end(),
std::ostream_iterator<int>(oss, ", "));
oss << "and ";
}
// else do nothing
oss << items.back();
std::cout << oss.str();
}
Output:
1, 1, 2, 3, 5, and 8
The following will work with any InputIterator input:
std::stringstream list;
auto it(std::begin(input)); //Or however you get the input
auto end(std::end(input));
bool first(true);
for (; it != end; ++it)
{
if (!first) list << ", ";
else first = false;
list << *it;
}
Or without an extra variable:
std::stringstream list;
auto it(std::begin(input)); //Or however you get the input
auto end(std::end(input));
if (it != end)
{
list << *it;
++it;
}
for (; it != end; ++it)
{
list << ", " << *it;
}
And if you want to do that with a map or other iterators that cannot do random access, as others have suggested, check for the first element:
std::stringstream query;
query << "select id from dueShipments where package in (";
for (auto it = packageList.begin(); it != packageList.end(); it++)
{
if (it != packageList.begin()) query << ", ";
query << it->second;
}
query << ")";

How to detect first or last element iterating over a container?

How to do the following in more stylish/short way?
for(i=container.begin(); i!=container.end(); ++i) {
if (i!=container.begin()) {
cout << ", ";
}
cout << *i;
j=i;
if (++j==container.end()) {
cout << "!" << endl;
}
}
Solutions like foreach are acceptable (actions on first and last elements need to be configurable, though).
P.S.
There are many answers that are handling first element, but not last. Here is what I mean by handling last element:
for(i=container.begin(); i!=container.end(); ++i) {
j=i;
if (i==container.begin()) {
cout << "[" << *i << "]" << endl;
} else if (++j==container.end()) {
cout << ", (" << *i << ")" << "!" << endl;
} else {
cout << ", " << *i;
}
}
Don't you think it's very easy to handle first element outside the cycle body? The real problem is the last one! I'm sorry for not being able to clarify the important point asking the question. I think I'll just accept the top ranked answer eventually.
Boost has next / prior which can sometimes help in such situations.
for(i=container.begin(); i!=container.end(); ++i) {
if (boost::next(i) == container.end()) {
std::cout << "!" << std::endl;
}
}
Although for this specific case, I'd simply output the first element, loop from second till last while always outputting the ',' and then output the '!' after the loop has ended. (as others have suggested already)
I don't see the point in moving the special cases inside the loop, and then checking inside the loop for them....
My advice here would be: there is no point in detecting anything within this loop !
Since your special cases are at the beginning and the end of your container, it is easy to remove their processing from within the loop.
The following function will print the contents of any container class whose elements can be <<'ed to an std::ostream:
template < class Container >
void print(Container const & container)
{
typename Container::const_iterator current = container.begin();
typename Container::const_iterator const end = container.end();
if (current != end)
{
std::cout << *current;
for (++current; current != end; ++current)
{
std::cout << ", " << *current;
}
std::cout << "!" << std::endl;
}
}
In your code,
if (i==container.end()) {
cout << "!" << endl;
}
will never happen.
My own approach would be to use the container size (I think size() is now constant time for all Standard Library containers). Maintain a count in the loop and you are at the end when count == size() - 1, and at the beginning when count == 0, obviously.
As container is not defined by you, I used the simplest - vector
template <class T>
string vector_join( const vector<T>& v, const string& token ){
ostringstream result;
for (typename vector<T>::const_iterator i = v.begin(); i != v.end(); i++){
if (i != v.begin()) result << token;
result << *i;
}
return result.str();
}
//usage
cout << vector_join( container, ", " ) << "!";
Shift the ++i a bit:
i = container.begin();
while(i != container.end()) {
if (i != container.begin()) {
cout << ", ";
}
cout << *i;
if (++i == container.end()) {
cout << "!" << endl;
}
}
template < class TContainerType>
void print(TContainerType const & i_container)
{
typename TContainerTypeconst ::const_iterator current = i_container.begin();
typename TContainerTypeconst ::const_iterator const end = i_container.end();
if(current != end)
{
std::cout << *current++;
while(current != end)
std::cout << ", " << *current++;
}
std::cout << "!" << std::endl;
}
Take the second part out of the loop.
for(i=container.begin(); i!=container.end(); ++i) {
if (i != container.begin()) {
cout << ", ";
}
cout << *i;
}
cout << "!" << endl;