Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

How would I make so that the last player name doesn't have a , so it's:

Player online:
Jim, John, Tony

and 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;
}
like image 990
tony Avatar asked Jan 24 '10 03:01

tony


People also ask

How do you find the last loop in foreach?

Use count() to determine the total length of an array. The iteration of the counter was placed at the bottom of the foreach() loop - $x++; to execute the condition to get the first item. To get the last item, check if the $x is equal to the total length of the array. If true , then it gets the last item.


8 Answers

Instead of thinking it like player + "," think of it as "," + player

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

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

of 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's name
else:
    output = ""

I like the look of that last one, I'll have to invent a language that actually works like that.

like image 126
Ponkadoodle Avatar answered Nov 02 '22 23:11

Ponkadoodle


change

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

with:

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

alternatively, you can do something like this if you don't want the comma in front of a name after the info.clear():

while(iter != Player::listPlayer.list.end())
{
    info += ", " + (*iter).second->getName();
    // ...
        player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, info.c_str()+2);
like image 45
Mark Elliot Avatar answered Nov 02 '22 23:11

Mark Elliot


(Borrowing wallacoloo's pseudocode)

output = "" 
for each player in players: 
    if output != "" 
        output += ", " 
    output += player's name 
like image 33
Carlos Gutiérrez Avatar answered Nov 03 '22 01:11

Carlos Gutiérrez


The easiest way is to simply remove the additional ", " in the end:

if (!info.empty()) {
  info.erase(info.size()-2);
}
like image 43
sth Avatar answered Nov 03 '22 01:11

sth


You can use string join from .NET or Boost or some other library or write your own. Although it might be overkill for that particular function, it's the kind of thing that you'll probably use elsewhere in that project, and that you'll definitely reuse in another project.

like image 43
JRL Avatar answered Nov 03 '22 00:11

JRL


If this were my code, I'd probably just check the string at the beginning of the loop and add the comma when it's not empty. It's nice to know how to handle similar situations when that workaround is not available, so here's an alternate:

while (iter != Player::listPlayer.list.end())
{
    info += (*iter).second->getName();
    ++iter;
    if (iter != Player::listPlayer.list.end())
        info += ", ";
    ++count;
    ...
}
like image 33
Mark Ransom Avatar answered Nov 02 '22 23:11

Mark Ransom


Instead of finding the last iteration, find the first iteration. Handle special cases at the beginning of the loop, have a definite "clean" state before doing the "real work," and perform the 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;
}
like image 44
Potatoswatter Avatar answered Nov 02 '22 23:11

Potatoswatter


My solution involves a variable that starts out as the empty string and is set to ", " after each iteration (which only has an effect 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;
}
like image 40
fredoverflow Avatar answered Nov 03 '22 01:11

fredoverflow