2010-01-24 24 views
6

¿Cómo puedo hacer para que el último nombre del jugador no tiene una , por lo que es:¿Cómo puedo reconocer la última iteración en C++ while loop?

Player online: 
Jim, John, Tony 

y no

Player online: 
Jim, John, Tony, 

Mi código es:

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

para reconocer última iteración, compruebe el estado del bucle de rizo interior. –

Respuesta

4

cambio

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

con:

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

Como alternativa, puede hacer algo como esto si no quiere que la coma que precede a un nombre después de la info.clear():

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

Usaría este enfoque, pero haré que while-loop esté subordinado a if-statement. No hay forma de que la primera prueba del tiempo tenga éxito si las if's no. – Boojum

+0

@Boojum, buena opción, voy a editar apropiadamente –

2

La forma más fácil es simplemente quitar el ", " adicional al final:

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

Si esto es C++ y que es un iterador STL, entonces si el iterador es un iterador de acceso aleatorio, entonces COU LD realidad preguntar

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

Si usted no está permitido hacer eso, entonces es probable que quiere poner el código dentro del ciclo while que imprime el nombre de un jugador en una función separada y llama a esa función en el primer elemento antes del ciclo while, luego llámelo dentro del ciclo while. Luego coloque el código que imprime la coma antes de que la llamada al nombre del jugador se imprima en el ciclo while. De esta forma, la primera llamada imprimirá solo el primer nombre, y luego el ciclo while siempre imprimirá primero una coma y luego el nombre del jugador, de modo que la salida finalice siempre con el nombre de un jugador.

7

En lugar de pensar como si fuera player + "," piensan que es "," + player

Por lo que podría hacer algo como esto (pseudo-código):

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

de si su idioma es compatible (lo que lo hace C++) :

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

Me gusta el aspecto de la última, tendré que inventar un lenguaje que realmente funcione así.

+0

sería mucho más rápido simplemente iterar solo sobre los jugadores 2..end (si existen). si solo alguien hubiera sugerido que ... –

+0

Sería de hecho. Nunca he usado iteradores de C++, no sabía que pudieras hacer eso con ellos. – Ponkadoodle

+0

eche un vistazo a mi respuesta =) solo necesita aumentar después de mirar el primer valor. –

2

(pseudocódigo prestatarios del wallacoloo)

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

solo como el código de wallacoloo, el tuyo sería mucho más rápido si miras al primer jugador fuera del bucle, de esa manera no presionas la declaración if para cada otro jugador ... –

+0

En serio, ¿mucho más rápido? ¿Cuánto cuesta? Más o menos del 25%? –

+0

Sí, pero: estaría duplicando código similar fuera y dentro del ciclo (imagínese que debe buscar o formatear el nombre del jugador), y: la comparación con nulos generalmente es muy optimizable. –

0

me escribió un código de ejemplo hace un momento para demostrar algunas maneras diferentes de hacer esto en C:

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

Desafortunadamente, no existe un método eso es claramente superior a los demás.Yo personalmente iría con un enfoque convencional (verifica explícitamente el primero o el último elemento) para mayor claridad y para evitar la duplicación del código. (Y definitivamente evite usar la versión goto en código C++.)

1

Si este fuera mi código, probablemente solo verifique la cadena al principio del ciclo y agregue la coma cuando no esté vacía. Es bueno saber cómo manejar situaciones similares cuando esa solución no está disponible, así que aquí tiene una alternativa:

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

Usted puede utilizar la cadena de unirse .NET o Boost o alguna otra biblioteca o escribir el suyo propio. Aunque puede ser excesivo para esa función en particular, es el tipo de cosa que probablemente utilizará en otro lugar en ese proyecto, y que definitivamente volverá a utilizar en otro proyecto.

1

En lugar de encontrar la última iteración, encuentre la primera iteración. Maneje casos especiales al comienzo del ciclo, tenga un estado definido de "limpieza" antes de realizar el "trabajo real" y realice el incremento al final.

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

Mi solución implica una variable que comienza como la cadena vacía y se fija a ", " después de cada iteración (que sólo tiene efecto después de la primera iteración). No es necesario verificar casos especiales.

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(); 
    ...... 
}