6
votes

Comment puis-je reconnaître la dernière itération dans une boucle C ++ pendant la boucle?

Comment ferais-je pour que le dernier nom du joueur n'a pas de , code> de sorte qu'il est: xxx pré>

et non p> xxx PRE>

Mon code est: P>

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;
}

c++

1 commentaires

Pour reconnaître la dernière itération, vérifiez la boucle de l'état de la boucle.


11 Réponses :


4
votes

Changer xxx

avec: xxx

Alternativement, vous pouvez faire quelque chose comme ça si vous ne voulez pas la virgule devant d'un nom après l'info.cpear (): xxx


1 commentaires

J'utiliserais cette approche, mais faites le subordonné de la boucle de temps imparti à la déclaration IF. Il n'y a aucun moyen le premier test de Why réussirait si le si le cas n'a pas.



2
votes

Le moyen le plus simple consiste simplement à supprimer le supplémentaire "," à la fin: xxx


0 commentaires

0
votes

S'il s'agit de C ++ et c'est un itérateur stl, alors si l'itérateur est un itérateur d'accès aléatoire, vous pouvez réellement demander

Si (iter + 1 == PLAER :: listplayer.list.end ())

Si vous n'êtes pas autorisé à faire cela, vous souhaitez probablement mettre le code à l'intérieur de la boucle tandis que imprime le nom d'un joueur dans une fonction distincte et appelez cette fonction sur le premier élément avant la boucle tandis que l'appelez-le. à l'intérieur de la boucle. Ensuite, mettez le code qui imprime la virgule avant l'appel sur le nom du lecteur Imprimer dans la boucle tandis que. De cette façon, le premier appel imprime simplement le prénom, puis la boucle tandis que la boucle imprimait toujours une virgule, puis le nom du joueur, de sorte que la sortie se termine toujours avec le nom d'un joueur.


0 commentaires

7
votes

au lieu de le penser comme lecteur + "," y penser comme "", "+ lecteur

afin que vous puissiez faire quelque chose comme ça (pseudo-code ): xxx

de si votre langue prend en charge (quel c ++ fait): xxx J'aime le look de cette Dernier, je devrai inventer une langue qui fonctionne réellement comme ça.


7 commentaires

Il serait beaucoup plus rapide de simplement itérer que sur les joueurs 2..end (s'ils existent). Si seulement quelqu'un avait suggéré que ..


Ce serait bien. Je n'ai jamais utilisé les itérateurs C ++, je ne savais pas que vous pourriez le faire avec eux.


Jetez un coup d'œil à ma réponse =) Vous avez juste besoin d'augmenter après avoir examiné la première valeur.


Presque, je pense que vous voulez dire pour chaque joueur dans les joueurs [1 ..]


Votre deuxième approche a besoin d'un contrôle pour vous assurer que la liste n'est pas vide.


@Mark, veuillez définir "beaucoup". Ce n'est pas "beaucoup plus rapide". Vous allez vous raser à propos d'une nanoseconde. Peut-être. Après avoir itérité à environ un million de fois


@Reverender assez juste, il semble en fait négligeable après tout ... Intérieur: Ideone.com/ddho1l7z , Extérieur: ideone.com/xxupikh4



3
votes

(Pseudocode de Wallacoloo empruntant)

output = "" 
for each player in players: 
    if output != "" 
        output += ", " 
    output += player's name 


5 commentaires

Tout comme le code de Wallacoloo, le vôtre serait beaucoup plus rapide si vous regardez le premier joueur en dehors de la boucle, de cette façon, vous ne frappez pas la déclaration IF pour chaque autre joueur ...


Sérieusement, "beaucoup plus rapide"? Combien? Plus ou moins de 25%?


Oui, mais: vous seriez dupliquer du code similaire à l'extérieur et à l'intérieur de la boucle (Imaginez que vous ayez dû rechercher ou formater le nom du joueur) et: la comparaison contre NULL est généralement très optimisable.


Cela ne fait pas de la même chose que la question indique dans le titre. Vous avez supposé qu'après les 10 premiers éléments, lorsque info.cpear () a été appelé, que l'élément suivant ne devrait pas avoir une virgule devant elle.


@Steve Jessop- droite, il détecte en fait la première itération. Pour le premier, il ajoute simplement le nom, pour le reste, il ajoute un , , puis le nom.



0
votes

J'ai écrit un exemple de code il y a quelque temps pour démontrer quelques façons différentes de le faire en C:

http://www.taenarum.com/csua/fun -with-c / délimiter.c

Malheureusement, il n'y a pas de méthode qui est clairement supérieure aux autres. Personnellement, j'irais avec une approche conventionnelle (vérifiez explicitement le premier ou le dernier élément) pour plus de clarté et pour éviter la duplication du code. (Et évitez certainement d'utiliser la version goto en code C ++.)


0 commentaires

1
votes

Si tel était mon code, je vérifierais probablement la chaîne au début de la boucle et ajouter la virgule quand ce n'est pas vide. Il est agréable de savoir comment gérer des situations similaires lorsque cette solution de contournement n'est pas disponible, alors voici un alternatif:

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


0 commentaires

2
votes

Vous pouvez utiliser une jointure de chaîne à partir de .NET ou boost ou une autre bibliothèque ou écrivez votre propre. Bien que cela puisse être surchargé pour cette fonction particulière, c'est le genre de chose que vous utiliserez probablement ailleurs dans ce projet et que vous réutilisez certainement dans un autre projet.


0 commentaires

1
votes

Au lieu de trouver la dernière itération, trouvez la première itération. Poignez des cas spéciaux au début de la boucle, ont un état «propre» défini avant de faire le «vrai travail» et effectuez l'incrément à la fin.

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;
}


0 commentaires

1
votes

Ma solution implique une variable qui commence comme la chaîne vide et est définie sur "", " code> après chaque itération (qui n'a qu'un effet après la première itération). Aucun cas particulier n'a besoin d'être vérifié.

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;
}


0 commentaires

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

0 commentaires