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;
Related
I can't seem to figure out why the program below is not running as intended.
After entering a negative integer value and breaking the first while loop in main, program control does not proceed.
I tried flushing the output stream at various key points but the issue persists.
#include <iostream>
#include <queue>
bool checkValidity(const std::queue<int>& q) {
for(auto i = q.front(); i != q.back(); ++i){
if (q.empty() || q.size() <= 1){
std::cout << "invalid entry, insufficient elements" << '\n';
return false;
break;
}
if (i > ++i) {
std::cout << "invalid entry, not properly sorted" << '\n';
return false;
break;
}
}
std::cout << "valid entry, properly sorted" << '\n';
return true;
}
const char* bool_cast(const bool b) {
return b ? "true" : "false";
}
int main () {
std::queue<int> numbers;
int temp;
std::cout << "Pushing..." << '\n';
while(temp >= 0){
std::cout << "Enter numbers: ";
std::cin >> temp;
if(temp >= 0){
numbers.push(temp);
}
}
bool ck = checkValidity(numbers);
std::cout << bool_cast(ck) << '\n';
std::cout << "{ ";
while(numbers.size() > 0){
std::cout << numbers.front();
numbers.pop();
std::cout << " ";
}
std::cout << "}" << '\n';
return 0;
}
You cannot iterate through the queue, therefore to iterate you need to copy the queue to another queue and then traverse by poping the elements from the queue. and comparing the elements.
Inline comments added for better understanding of the code.
bool checkValidity(const std::queue<int>& q) {
if (q.empty() || q.size() <= 1){ // This can be outside the loop and checked only onces
std::cout << "invalid entry, insufficient elements" << '\n';
return false;
}
std::queue<int> numbers=q; // a new queue to copy the queue
int first=numbers.front(); // to compare we need to variable first and second
numbers.pop();// pop the first value,as it is stored in first variable
int second;
while(!numbers.empty()){
second=numbers.front();
numbers.pop();
if (first> second) { // compare the first and second variable
std::cout << "invalid entry, not properly sorted" << '\n';
return false;
break;
}
first=second; // assign second to first and traverse the reamining queue
}
std::cout << "valid entry, properly sorted" << '\n';
return true;
}
Hope this help.
Inherited from std::queue and use its protected member Container c; to access begin() and end() of the underlying container as previously done here std::queue iteration.
#include <iostream>
#include <queue>
#include <deque>
#include <iterator>
template<typename T, typename Container=std::deque<T> >
class iterable_queue : public std::queue<T,Container>
{
public:
typedef typename Container::iterator iterator;
typedef typename Container::const_iterator const_iterator;
iterator begin() { return this->c.begin(); }
iterator end() { return this->c.end(); }
const_iterator begin() const { return this->c.begin(); }
const_iterator end() const { return this->c.end(); }
};
bool checkValidity(iterable_queue<int>& q) {
if (q.empty() || q.size() <= 1){
std::cout << "invalid entry, insufficient elements" << '\n';
return false;
}
while(q.size()){
auto i = q.begin();
auto j = ++q.begin();
for(; i < q.end() && j < ++q.end();){
std::cout << *i << " " << *j << '\n';
if (*(i) > *(j)) {
std::cout << "invalid entry, not properly sorted" << '\n';
return false;
}
i++, j++;
}
std::cout << "valid entry, properly sorted" << '\n';
return true;
}
std::cout << "invalid entry, insufficient elements" << '\n';
return false;
}
const char* bool_cast(const bool b) {
return b ? "true" : "false";
}
int main () {
iterable_queue<int> numbers;
int temp;
std::cout << "Pushing..." << '\n';
while(temp >= 0){
std::cout << "Enter numbers: ";
std::cin >> temp;
if(temp >= 0){
numbers.push(temp);
}
}
bool ck = checkValidity(numbers);
std::cout << bool_cast(ck) << '\n';
std::cout << "{ ";
while(numbers.size() > 0){
std::cout << numbers.front();
numbers.pop();
std::cout << " ";
}
std::cout << "}" << '\n';
return 0;
}
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 & );
This is just for one of the exercises in my book, where it asks me to search through a vector for a specific name and return a score from another corresponding vector once the name has been found. If the name isn't found, it'll return the message "Name not found!"
int main()
{
vector<string>name;
vector<int>score;
string n = "0";
int s = 0;
while (cin >> n >> s && n != "NoName") {
for (int i = 0; i < name.size(); ++i)
if (n == name[i]) {
cout << "Error! Name is already in database!" << '\n';
break;
}
name.push_back(n);
score.push_back(s);
}
for (int i = 0; i < name.size(); ++i)
cout << "(" << name[i] << " " << score[i] << ")" << '\n';
cout << "Type in a name to find the score" << '\n';
string search = "0";
cin >> search;
for (int i = (name.size() - 1); i >= 0; i = i - 1) {
if (search == name[i])
cout << "Score is " << score[i] << '\n';
else
cout << "Name not found!" << '\n';
}
}
The above is my code. The only problem I'm having is that it'll loop through the vector and return "Name not found!" multiple times because it searches each individual position. I only want it to return the message once the whole vector has been searched. I've tried googling it, and I've found something like this:
#include <algorithm>
...
std::vector<std::string>::const_iterator it = std::find(vec.begin(), vec.end(), "some string");
if (it != vec.end())
{
std::cout << "Found '" << *it << "' in the vector." << std::endl;
}
which, unfortunately, I don't quite understand.
std::vector<std::string>::const_iterator it = std::find(vec.begin(), vec.end(), "some string");
This searches for the string "some string" in the range [vec.begin(), vec.end()[ and returns an iterator to the element in the range if it is found. If it is not found, the end of the range (vec.end()) is returned.
So if (it != vec.end()) is saying if (the string was found).
Regarding your original code and the unwanted prints, there are several ways of fixing that. One way would be:
int i;
for (i = (name.size() - 1); i >= 0; i = i - 1) {
if (search == name[i]) break; // exit the loop as soon as the element is found
}
if (i >= 0) {
cout << "Score is " << score[i] << '\n';
} else {
cout << "Name not found!" << '\n';
}
std::vector<std::string>::const_iterator it = std::find(name.begin(), name.end(), name_to_search);
Please refer to function template std::find. It searches range [name.begin(), name.end()) and compare every element with "name_to_search". It returns an iterator to the first element that is equal to "name_to_search".
If no elements match, the function returns name.end().
P.S. You can also go through the range like this:
int i = 0;
for (; i < name.size(); i++) {
if (search == name[i]){
cout << "Score is " << score[i] << '\n';
break;
}
}
if(i == name.size()){
cout << "Name not found!" << '\n';
}
Just a question, on the use of const_iterator vs just iterator. More specifically with the use of distance(). Below is some basic code that just craps out a list of "fav_games" that the user enters (earlier in the application). I wanted to also crap out the 'index' of the vector so as to print out a numbered list.
Partial Code:
int main()
{
vector<string> fav_games;
vector<string>::const_iterator iter; // const_iterator no worky with "distance()"
if (fav_games.size() > 0) {
cout << "\n\nCurrent game list: \n";
for (iter = fav_games.begin(); iter != fav_games.end(); ++iter)
{
cout << distance(fav_games.begin(), iter) << ". " << *iter << endl;
}
}
return 0;
}
My question is why, "const_iterator" will not work, where I am forced to use "iterator" instead. Looking for the 'theory' behind it. "distance()" appears to expecting and "iterator" -- not "const_iterator". ..Why?
Just for reference the compile error if I use "const_iterator":
Error 1 error C2782: 'iterator_traits<_Iter>::difference_type std::distance(_InIt,_InIt)' : template parameter '_InIt' is ambiguous z:\micah\c++\favgames\favgames\favgames.cpp 49 1 favgames
Thanks!
Try this instead:
vector<string>::const_iterator b, iter, e;
if (fav_games.size() > 0) {
cout << "\n\nCurrent game list: \n";
for (b = fav_games.begin(), iter = b, e = fav_games.end(); iter != e; ++iter)
{
cout << distance(b, iter) << ". " << *iter << endl;
}
}
distance has no problem with two const_iterator instances, or two iterator instances. Your mistake was in mixing them.
Still, making O(n) calls to distance is crazy. Just use a counter:
vector<string>::const_iterator iter, e;
size_t i;
if (fav_games.size() > 0) {
cout << "\n\nCurrent game list: \n";
for (i = 0, iter = fav_games.begin(), e = fav_games.end(); iter != e; (++iter), (++i))
{
cout << i << ". " << *iter << endl;
}
}
In C++11 and later, one may of course go one step further and avoid explicit use of the iterators at all:
if (fav_games.size() > 0) {
int i = 0;
cout << "\n\nCurrent game list: \n";
for (const string& game : fav_games)
{
cout << (i++) << ". " << game << endl;
}
}
I have this code
void Options::printHelp() {
hash_map<string, Option>::iterator iter;
for ( iter = options.begin(); iter != options.end(); iter++ ) { //<- this one
cout << iter->first;
cout << "\t";
cout << iter->second.getDescription() << "\n";
}
}
Definition of options
class Options {
...
hash_map<string, Option> options;
private:
....
}
XCode (Which is the IDE i’m using) marks the area "iter != options.end()" and gives me the error specified in the title.
I Can’t seem to figure out why.
(Option, btw, is a small container class, that holds 2 strings and an enum)
It's hard to say what exactly the problem is without seeing the definition of options. My guess is it's not of hash_map<string, Option> type.
If you write your code like the this though, you shouldn't be running into that sort of problems:
for ( auto iter = options.begin(), end = options.end(); iter != end; ++iter ) {
cout << iter->first;
cout << "\t";
cout << iter->second.getDescription() << "\n";
}
Or even better:
for ( auto &i: options )
cout << i.first << '\t' << i.second.getDescription() << '\n';
This requires C++11.