How can I find out the last iteration in a C ++ while loop?

How can I make sure that the name of the last player does not have, so this:

 Player online: Jim, John, Tony 

but not

 Player online: Jim, John, Tony, 

My code is:

 bool Commands::whoIsOnline(Creature* c, const std::string &cmd, const std::string &param) { Player* player = dynamic_cast<Player*>(c); if (player) { player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, "Players online: "); AutoList<Player>::listiterator iter = Player::listPlayer.list.begin(); std::string info; int count = 0; while (iter != Player::listPlayer.list.end()) { info += (*iter).second->getName() + ", "; ++iter; ++count; if (count % 10 == 0) { player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, info.c_str()); info.clear(); } } if (!info.empty()) player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, info.c_str()); } return true; } 
+6
c ++
source share
11 answers

Instead of thinking that player + "," thinks of it as "," + player

So you can do something like this (psuedo-code):

 onFirstName = true output = "" for each player in players: if onFirstName: onFirstName = false else: output += ", " output += player name 

if your language supports it (which C ++ does):

 if length of players > 0: output = players[0] for each player in players except players[0]: output += ", " + player name else: output = "" 

I like the look of this last one, I have to come up with a language that really works that way.

+7
source share

change

 while(iter != Player::listPlayer.list.end()) { info += (*iter).second->getName() + ", "; //... 

from:

 if(iter != Player::listPlayer.list.end()){ info += (*iter).second->getName(); ++iter; while(iter != Player::listPlayer.list.end()){ { info += ", " + (*iter).second->getName(); //... } //... } 

you can do something like this if you do not want the comma before the name after info.clear ():

 while(iter != Player::listPlayer.list.end()) { info += ", " + (*iter).second->getName(); // ... player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, info.c_str()+2); 
+4
source share

The easiest way is to simply remove the extra ", " at the end:

 if (!info.empty()) { info.erase(info.size()-2); } 
+2
source share

(Borrowing wallacoloo pseudocode)

 output = "" for each player in players: if output != "" output += ", " output += player name 
+2
source share

You can use string concatenation from .NET or Boost or another library or write your own. Although this may be redundant for this particular function, it is something that you are likely to use elsewhere in this project, and that you will definitely reuse it in another project.

+2
source share

If this were my code, I would most likely just check the line at the beginning of the loop and add a comma when it is not empty. It's nice to know how to handle these situations when this workaround is not available, so here is an alternative:

 while (iter != Player::listPlayer.list.end()) { info += (*iter).second->getName(); ++iter; if (iter != Player::listPlayer.list.end()) info += ", "; ++count; ... } 
+1
source share

Instead of finding the last iteration, find the first iteration. Handle special cases at the beginning of the cycle, determine the “clean” state before doing the “real work,” and increment at the end.

 while (iter != Player::listPlayer.list.end()) { if ( count != 0 ) { info += ", "; if (count % 10 == 0) { player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, info.c_str()); info.clear(); } } // invariant: info is clean and ready to accept data info += (*iter).second->getName(); ++iter; ++count; } 
+1
source share

My solution includes a variable that starts as an empty string and is set to ", " after each iteration (which has an effect only after the first iteration). No special cases need to be checked.

 template<class ForwardIterator> std::string sequence_to_string(ForwardIterator begin, ForwardIterator end) { std::string output; const char* delimiter = ""; for (ForwardIterator it = begin; it != end; ++it) { output += delimiter; output += *it; delimiter = ", "; } return output; } 
+1
source share

If it is C ++ and it is an STL iterator, then if the iterator is a random access iterator, you can really ask

if (iter + 1 == Plaer :: listPlayer.list.end ())

If you are not allowed to do this, you probably want to put the code inside the while loop that prints the player’s name in a separate function and call that function in the first element before the while loop, and then call it inside the while loop. Then put code that prints a comma before invoking the print player name in the while loop. Thus, the first call will print only the first name, and then the while loop will always print the comma first and then the player’s name, so the output always ends with the player’s name.

0
source share

Some time ago I wrote some code examples to demonstrate several different ways to do this in C:

http://www.taenarum.com/csua/fun-with-c/delimiter.c

Unfortunately, there is no method that is clearly superior to others. For clarity, I personally would like to use the usual approach (explicitly check for the first or last element) and avoid duplication of code. (And definitely avoid using the goto version in C ++ code.)

0
source share
 ... std::string info; ... while (iter != Player::listPlayer.list.end()) { if(info.size() > 0) info += ","; info += (*iter).second->getName(); ...... } 
0
source share

All Articles