2012-03-29 5 views
0

Ich habe eine ganze Tabelle in std::deque<record *> gespeichert und ich muss dem Benutzer erlauben, die Tabelle für jede Spalte zu sortieren. Die Tabelle wird dem Benutzer in einem Listenfeldformat präsentiert.Wie man std :: map vergleichen kann, um mit mehreren Datentypen zu arbeiten?

Jeder Datensatz besteht aus mehreren Strings (Struct of Strings). Die Felder haben jedoch unterschiedliche Typen, d. H. Zeit (HH: MM: SS), Gleitkommazahl und Zeichenfolgen, obwohl sie alle als Zeichenfolgen gespeichert sind.

Der Benutzer darf eine dieser Spalten sortieren. Wenn der Benutzer auf die Spalte klickt, speichere ich jeden Datensatz in einer Multimap, so dass die Tabelle für den Benutzer in einem sortierten Format angezeigt wird.

Da die Spalten jedoch unterschiedliche Typen haben, wie schreibe ich eine einzige Vergleichsmethode, die all diese effizient behandelt?

Ich dachte an die folgenden Arten

  1. Verwenden Sie verschiedene Karten für jeden Typ und schreiben eine Funktionsklasse für jede der Karten vergleichen.
  2. Verwenden Sie eine einzelne Map mit einer Vergleichsklasse, die alle drei verschiedenen Typen behandelt. Für jede Einfügung muss die Vergleichsklasse jedoch den Typ bestimmen und entsprechend einfügen.

Gibt es einen besseren Weg als diese beiden?

Beispiel:

struct ltDataCompare 
{ 

    bool operator()(const CString& csData1, const CString& csData2) const 
    { 

     if (isTimeFormat(csData1) && isTimeFormat(csData1)) 
     { 
       // Do time relevant comparision 
      } 
      else if (isNumberFormat(csTime1) && isNumberFormat(csTime2)) 
     { 
      double dPrice1 = atof((LPCTSTR)csTime1); 
      double dPrice2 = atof((LPCTSTR)csTime2); 

      return (dPrice1 < dPrice2); 
     } 
     return (csTime1 < csTime2); 
    } 
}; 

std::multimap<CString,list_record_t*,ltDataCompare> _mapAllRecords; // Used only for sorting 
+0

Was vergleichen Sie? Ist es sinnvoll, beispielsweise einen Float mit einem String zu vergleichen? Edit: Entschuldigung, ich verstehe was du meinst. Sie möchten nach einem oder mehreren Feldern im Datensatz sortieren. Nun, Sie können das mit einer Feldaufzählung machen, die Sie in Ihre Sortierfunktion (oder Lambda) übergeben, und dann den entsprechenden Wert in der Vergleichsfunktion in Abhängigkeit vom Aufzählungswert verwenden. – Robinson

+0

Könnten Sie bitte ein Beispiel Robinson zeigen? – user373215

+0

Robinson, alle Felder sind als Strings gespeichert. Ich muss den Typ des Feldes bestimmen und entsprechende Sortierung/Vergleich durchführen. – user373215

Antwort

1

Sie können nicht neu sortieren eine map oder multimap - sobald ein Element eingefügt wird, wird seine Position verriegelt. Es wäre besser, einen anderen Container wie einen vector zu verwenden und es bei Bedarf zu sortieren.

Das Schöne an einer Vergleichsklasse ist, dass sie State enthalten darf. Sie können ein Element mit einer Konstanten oder einem Zeiger haben, um zu bestimmen, welche Vergleichsmethode verwendet werden soll.

Sie können nach dem gleichen Prinzip auswählen, nach welchem ​​Feld sortiert werden soll.

struct ltDataCompare 
{ 
    ltDataCompare(int field, int method) : m_field(field), m_method(method) {} 
    bool operator()(const record& left, const record& right) const 
    { 
     if (m_method == enumTimeFormat) 
      return CompareTimes(left[m_field], right[m_field]); 
     else if (m_method == enumNumberFormat) 
      return CompareNumbers(left[m_field], right[m_field]); 
     // ... 
    } 
    int m_field; 
    int m_method; 
}; 

std::sort(table.begin(), table.end(), ltDataCompare(0, enumTimeFormat)); 
+0

Mark, ich verstehe map kann nicht geordert werden. Ich benutze Maps/Multimap, nur um die Datensätze in Ordnung zu halten. Sobald diese sortiert sind, brauche ich die Karte/Multimap nicht. Ich kann sie zerstören. Können Sie ein Beispiel/einen Link anzeigen? – user373215

+0

Können Sie ein Beispiel/einen Link für "Sie können das gleiche Prinzip verwenden, um zu wählen, welches Feld zu sortieren". – user373215

+0

@ user373215: Wenn Sie sie nur zum Sortieren verwenden, verwenden Sie einen normalen Container (zB 'std :: vector <>' oder 'std :: deque <>') + 'std :: sort' und ziehen Sie die assoziativen Container ab insgesamt. – ildjarn

0

Sie könnten elegantere darüber sein - ich weiß nicht, dass Sie sich keine Arbeit sparen würde - wenn Sie für jeden der Typen eine Klasse mit einer < Operator in sich hatte. Wenn Sie eine übergeordnete Klasse haben, die einen virtuellen < Operator hat, dann können Sie es als Schlüsseltyp verwenden, wie in

std::multimap< superclass, list_record_t > 

Jetzt können Sie eine der Kind-Typen als die eigentlichen Schlüssel verwenden (so lange, wie Sie konsequent bleiben). Eigentlich bin ich mir nicht sicher, ob das schlauer oder eleganter ist. Cleverer ist in der Regel eine schlechte Sache (wie es mehr obskur/weniger wartbar bedeutet). Wenn es für weniger Codezeilen sorgt, ist das normalerweise eine gute Sache.

Verwandte Themen