2010-01-24 3 views
6

Wie würde ich machen, so dass der letzte Spieler Name ein , haben nicht so ist es:Wie kann ich die letzte Iteration in einer C++ while-Schleife erkennen?

Player online: 
Jim, John, Tony 

und nicht

Player online: 
Jim, John, Tony, 

Mein Code ist:

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

letzte Iteration zu erkennen, prüft Looping die Schleifenbedingung. –

Antwort

4

Änderung

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

mit:

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

alternativ können Sie etwas tun, wenn Sie nach dem info.clear nicht das Komma vor einem Namen wollen():

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

Ich würde diesen Ansatz verwenden, aber die While-Schleife unterordnen die If-Anweisung. Es gibt keine Möglichkeit, dass der erste Test erfolgreich wäre, wenn die if's nicht funktionieren würden. – Boojum

+0

@Boojum, guten Ruf, ich werde entsprechend bearbeiten –

2

Der einfachste Weg, ist, einfach die zusätzliche ", " am Ende zu entfernen:

if (!info.empty()) { 
    info.erase(info.size()-2); 
} 
0

wenn dieses C++ ist, und das ist ein Iterator STL, dann, wenn der Iterator ein Random-Access-Iterator ist, können Sie dann cou ld fragen tatsächlich

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

Wenn Sie das nicht tun dürfen, dann werden Sie wahrscheinlich Ich möchte den Code in die while-Schleife einfügen, die den Namen eines Players in einer separaten Funktion ausgibt, und diese Funktion für das erste Element vor der while-Schleife aufrufen und dann in der while-Schleife aufrufen. Setzen Sie dann den Code, der das Komma vor dem Aufruf des Playernamens druckt, in die While-Schleife. Auf diese Weise wird beim ersten Aufruf nur der Vorname gedruckt, und dann wird in der while-Schleife immer zuerst ein Komma und dann der Name des Players gedruckt, so dass die Ausgabe immer mit dem Namen des Spielers endet.

7

Statt es wie player + "," denken an sie zu denken, als "," + player

So könnte man so etwas wie diese (Pseudocode) tun:

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

von, wenn Ihre Sprache unterstützt (Welche C++ tut) :

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

Ich mag das Aussehen der letzten, ich muss eine Sprache erfinden, die tatsächlich so funktioniert.

+0

es wäre viel schneller, einfach nur über Spieler 2.End (wenn sie existieren) zu iterieren. wenn nur jemand das vorgeschlagen hätte .. –

+0

Es wäre in der Tat. Ich habe nie C++ - Iteratoren verwendet, ich wusste nicht, dass Sie das mit ihnen machen könnten. – Ponkadoodle

+0

werfen Sie einen Blick auf meine Antwort =) Sie müssen nur erhöhen, nachdem Sie den ersten Wert betrachtet haben. –

2

(Borrowing wallacoloo der Pseudo-Code)

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

nur Wie der Code von wallacoloo, wäre dein Code viel schneller, wenn du den ersten Spieler außerhalb der Schleife betrachtest, so dass du nicht die if-Anweisung für jeden anderen Spieler triffst ... –

+0

Ernsthaft, "viel schneller"? Wie viel? Mehr oder weniger als 25%? –

+0

Ja, aber: Du würdest einen ähnlichen Code außerhalb und innerhalb der Schleife duplizieren (stell dir vor, du müsstest den Spielernamen suchen oder formatieren), und: der Vergleich mit null ist normalerweise sehr optimierbar. –

0

Ich schrieb einige Code Probe vor einer Weile ein paar verschiedene Möglichkeiten, dies zu tun in C zu demonstrieren:

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

Leider gibt es keine Methode, das ist den anderen deutlich überlegen.Ich würde persönlich mit einem konventionellen Ansatz gehen (explizit nach dem ersten oder letzten Element suchen), um Klarheit zu schaffen und Doppelcodierung zu vermeiden. (Und die Verwendung der goto Version in C++ Code definitiv vermeiden.)

1

Wenn dies mein Code wäre, würde ich wahrscheinlich nur die Zeichenfolge am Anfang der Schleife überprüfen und das Komma hinzufügen, wenn es nicht leer ist. Es ist schön zu wissen, wie ähnliche Situationen zu handhaben, wenn diese Problemumgehung nicht verfügbar ist, also hier eine alternative:

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

können Sie verwenden Zeichenfolge von .NET verbinden oder Erhöhung oder eine andere Bibliothek oder schreiben Sie Ihre eigenen. Auch wenn es für diese spezielle Funktion vielleicht zu viel ist, wird es wahrscheinlich an einer anderen Stelle in diesem Projekt verwendet und in einem anderen Projekt wiederverwendet.

1

Suchen Sie statt der letzten Iteration die erste Iteration. Behandeln Sie spezielle Fälle am Anfang der Schleife, haben Sie einen bestimmten "sauberen" Zustand, bevor Sie die "echte Arbeit" ausführen, und führen Sie das Inkrement am Ende durch.

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

Meine Lösung beinhaltet eine Variable, die als leere Zeichenfolge beginnt und an ", " nach jeder Iteration eingestellt (die nur eine Wirkung nach der ersten Iteration hat). Es müssen keine speziellen Fälle überprüft werden.

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
...  
std::string info; 
... 
while (iter != Player::listPlayer.list.end()) 
{ 
    if(info.size() > 0) 
    info += ","; 
    info += (*iter).second->getName(); 
    ...... 
} 
Verwandte Themen