2010-10-30 18 views
5

controllare il codice seguente:Utilizzando comparatore per STL set

string toLowerCase(const string& str) { 
    string res(str); 
    int i; 

    for (i = 0; i < (int) res.size(); i++) 
     res[i] = (char) tolower(res[i]); 

    return res; 
} 

class LeagueComparator 
{ 
public: 
    bool operator()(const string& s1, const string& s2) 
    { 
     return toLowerCase(s1) < toLowerCase(s2); 
    } 
}; 

int main() 
{ 
    set<string, LeagueComparator> leagues; 
    set<string, LeagueComparator>::iterator iter; 

    leagues.insert("BLeague"); 
    leagues.insert("aLeague"); // leagues = {"aLeague", "BLeague"} 
    leagues.insert("ALeague"); 

    for (iter = leagues.begin(); iter != leagues.end(); iter++) 
     cout << *iter << endl; 

    return 0; 
} 

L'output è:

aLeague 
BLeague 

che è scioccante per me. Ho pensato (e in attesa) l'output sarà:

aLeague 
ALeague 
BLeague 

Prima dell'esecuzione del leagues.insert("ALeague");, il leagues contiene "aLeague" e "BLeague". La mia domanda è, mentre eseguo leagues.insert("ALeague"); perché la macchina tratta "ALeague" == "aleague"? Secondo la mia comprensione, non esiste alcun elemento "ALeague" in leagues. Quindi "ALeague" deve essere inserito in leagues. Il comparatore dovrebbe determinare dove mettere "ALeague".

Grazie in anticipo.

PS: Per favore non mi colpisca per l'utilizzo del cast di stile C. : P Sono troppo pigro per digitare static_cast.

+0

Il fatto che ci si sente si deve lavorare per eseguire un C getto stile ++ è uno dei principali ragione C++ calchi stile esisti - vale a dire che si dovrebbe evitare qualsiasi tipo di fusione in C++. In questo caso è necessario rimuovere completamente i cast e utilizzare invece i tipi corretti. Cioè invece di '(int) res.size()', rimuovi il cast e cambia il tipo di 'i' in' unsigned'. –

+0

Inoltre, 'i' deve essere dichiarato nel ciclo, non al di fuori del ciclo. E in C++, toLowerCase dovrebbe probabilmente chiamare 'std :: transform (str.begin(), str.end(), str.begin(), std :: ptr_fun (tolower))' invece di scrivere un ciclo esplicito. –

+0

@Billy ONeal: grazie.ho bisogno di essere usato per usare 'transform()'. che 'toLowerCase' è stato scritto da me molti anni fa. Penso che non sapessi di 'transform' in quel momento. aggiornerò il mio codice base. – Donotalo

risposta

14

Il tuo comparatore, grazie allo toLowerCase, dice che "aLeague" == "ALeague". Poiché (secondo il tuo comparatore) "aLeague" < "ALeague" == false e "ALeague" < "aLeague" == false, devono essere equivalenti. E inserire un elemento equivalente in un set non fa nulla.

+3

+1. Si noti che il comparatore non sta stabilendo l'uguaglianza, sta stabilendo l'equivalenza. C'è una differenza w.r.t. documentazione standard e STL. –

+0

Grazie, modificando il mio post. –

3

Dato il comparatore che hai fornito, "ALeague" è in effetti equivalente "aLeague".

Dato due valori x ed y, e una minore di confronto z:

  • Se z (x, y) è vera, allora x è minore di y
  • Se z (y, x) è vero, allora y è minore di x
  • Se nessuno è vero, allora x è equivalente a y
  • Se entrambi sono vere, allora si ha un comparatore guasto.
+0

+1, ma un leggero problema con il terzo proiettile w.r.t. Documenti STL. C'è una distinzione tra uguaglianza e equivalenza. Un comparatore inferiore a quello non può stabilire l'uguaglianza, solo l'equivalenza. –

+0

@Billy ONeal: secondo STL doc (non ce l'ho), quali sono le definizioni di 'uguaglianza' e' equivalenza'? – Donotalo

+0

@Donotalo: l'uguaglianza è il confronto usando un comparatore di uguaglianza, o 'operator =='. Equivalenza è lo stato in cui meno di un comparatore o 'operatore <' restituisce false per entrambi gli ordini degli argomenti, come specificato qui. Concettualmente, è la differenza tra [uguaglianza comparabile] (http://www.sgi.com/tech/stl/EqualityComparable.html) e [meno che confrontabile] (http://www.sgi.com/tech/stl/ LessThanComparable.html). –

4

Quando si inserisce un valore in un set, l'oggetto controlla se contiene già quel valore. L'oggetto LeagueComparator confronta ALeague con gli altri due valori già presenti nel set. Determina che il valore esistente aLeague non è né maggiore né minore della nuova voce proposta (ALeague), pertanto devono essere uguali e quindi non procedere con l'inserimento. Il set rimane con solo due elementi. Questo è l'obiettivo principale di fornire un oggetto di confronto clienti, in modo da poter controllare come il set determina se due elementi corrispondono.

+0

+1. Si noti che per essere coerenti con i documenti STL, la maggior parte degli usi di "uguale" qui devono essere sostituiti con "equivalente". Meno di comparatori non possono stabilire l'uguaglianza. –

0

Sostituire il LeagueComparator con

class LeagueComparator 
{ 
public: 
    bool operator()(const string& s1, const string& s2) 
    { 
     return toLowerCase(s1) < toLowerCase(s2) || 
       !(toLowerCase(s2) < toLowerCase(s1)) && s1 < s2; 
    } 
}; 
+0

Equivale a specificare nessun comparatore. Il tuo comparatore restituisce semplicemente 's1

+0

Non è vero. 's1 =" b "', 's2 =" A "'. Il mio comparatore restituisce 'false' a causa di' false || ! true && true = false'. 's1

Problemi correlati