2011-10-07 13 views
7

Sto tentando di creare un piccolo programma che elabora i file INI, da utilizzare in un progetto successivo, prima riducendone le dimensioni una volta caricato in memoria. Così,Rimozione elementi vuoti da un vettore di stringhe

dove vline è un vettore contenente il contenuto del file

for (unsigned int i = 0; i < vLine.size(); i++) 
{ 
    if (!vLine[i].find(';', 0)) 
    { 
     vLine[i].erase(); 
    } 
} 

al momento della stampa vline, sarò lasciato con spazi dove una volta una linea che inizia con un punto e virgola esisteva, come

1.  
2. property 
3. property 
4. 
5. property 

L'uso di resize() sembra rimuovere l'ultimo elemento dall'elenco piuttosto che rimuovere queste parti vuote. Lo stesso problema esiste dove rimuovo le righe che contengono solo spazi bianchi con cancella().

È possibile rimuovere questi elementi vuoti mantenendo l'ordine di vLine?

(Scuse per non usare iteratori in questo.)

+0

Re: (scuse per non usare iteratori in questo.) - Perché non usare iteratori? –

+0

Mancanza di conoscenza per quanto riguarda il loro uso corretto. Sembra (sembrava?) Possibile farlo senza di loro. – JGrey

+1

Puoi rimuovere le linee dal vettore piuttosto che cancellare semplicemente il contenuto della stringa (che è ciò che 'vLine [i] .erase()' fa, no? Chiama 'vLine.erase()' dato che cancella dal 'vector' Quindi riscrivi il file in uscita, un modo idiomatico per farlo è l'espressione [erase-remove idiom] di C++ (http://en.wikipedia.org/wiki/Erase-remove_idiom), sebbene tu voglia usare 'std :: remove_if 'da '' per usare un condizionale – birryree

risposta

8

Questo:

vLine[i].erase(); 

non cancella vLine[i] dal vettore. L'espressione vLine[i] restituisce un riferimento all'elemento nell'indice i. Quindi, supponendo che sia di tipo , la chiamata di funzione erase() chiama effettivamente string::erase() sull'elemento, non vector::erase() sul vettore. Tutto quello che stai facendo è rendere quel particolare elemento vuoto.

Ciò che probabilmente si desidera è qualcosa di simile:

vLine.erase(vLine.begin() + i); 

Questo rimuove in realtà l'elemento dal vettore. Ora, questo invalida tutti gli iteratori correnti al vettore, e gli indici non saranno più giusti. Questa è una situazione in cui hai davvero bisogno di usare gli iteratori.

std::vector<std::string>::iterator i = vLine.begin(); 
while(i != vLine.end()) 
{ 
    if(i->find(';', 0) != std::string::npos) 
    { 
     i = vLine.erase(i); 
    } 
    else 
    { 
     ++i; 
    } 
} 

Ma c'è un modo ancora più semplice per fare questo: utilizzare l'algoritmo standard std::remove_if() con un funtore quindi chiamare vLine.erase().

struct HasSemicolon 
{ 
    bool operator()(const std::string& s) 
    { 
     return s.find(';', 0) != std::string::npos; 
    } 
}; 

// ... 

vLine.erase(std::remove_if(vLine.begin(), vLine.end(), HasSemicolon()), vLine.end()); 

Se è possibile utilizzare un compilatore C++ 11, allora si può anche usare espressioni lambda per essere ancora più conciso.

+0

Molto in obbligo, in Silico, mi prenderò il tempo di imparare gli iteratori e di modificare la mia applicazione di conseguenza – JGrey

+0

Potresti aggiungere un esempio usando C++ 11 lambda? per capirlo per la maggior parte di un'ora ora, ma sono orribile a leggere i documenti C++. –

+0

@QPaysTaxes http://en.cppreference.com/w/cpp/algorithm/remove ha un esempio con un lambda. – arekolek

4

Utilizzare la cancellazione/rimuovere-linguaggio, preferibilmente con un lambda da C++ 11:

foo.erase(std::remove_if(foo.begin(), foo.end(), 
         [](const std::string& s) 
         { return s.find(';', 0); })); 
7

Il problema è nella logica per rimuovere gli elementi. Quando si incontra un elemento nell'indice i che si desidera cancellare, si cancella il suo valore, ma non lo si rimuove dal vettore.

Il metodo standard e semplice per fare quello che vuoi fare è std::remove_if:

vLine.erase(
    std::remove_if(
     vLine.begin(), 
     vLine.end(), 
     [](std::string const& s) { return s.size() != 0 && s.front() == ';'; }), 
    vLine.end()); 
Problemi correlati