3-dimensionale map



  • Hallo,

    ich habe in einer Klasse eine Konfiguration als map<string,string> realisiert.
    nun versuche ich eine dritte dimension hinzuzufügen (section einer Ini-Datei als int [index in einer 2. map<int,string>])

    map selbst versteht scheinbar nur 2 Elemente, wie könnte ich das anders realisieren?

    Gruß Frank



  • Ich verstehe nicht, was du bzgl map<string,string> mit "eine dritte dimension hinzufügen" meinst.

    Ich rate einfach mal:

    - map< string, pair<int,string> >
    - map< pair<string,int>, string >
    - map< string, map<int, string> >
    - ...



  • Die straightforward Lösung wäre wohl eine map<string, map<string, string>> .
    Ansonsten würde ich mir überlegen, ob du den Sectionname nicht einfach vorne an den Key dranhängen kannst. Außerdem würd ich mir überlegen, ob ich nicht eher eine unordered_map will.



  • danke für die schnellen Antworten

    ich wusste gar nicht, dass sowas geht...

    in meinem Fall wäre das dann ja

    map< int, map<string, string> >

    wobei int der index (bzw. iterator) des sectionnamens in einer 2. map (zuweisung zu einem Sectionnamen)

    könnte zwar auch einen vector nehmen, aber dann habe ich probleme mit dem index, wenn ich da werte lösche..ich brauche einen unveränderlichen index.

    wenn ich den Sectionnamen bei jedem Item hinterlege (map< string, map<string, string> > ) habe ich einen massiven speicherverbrauch (auch wenn das bei aktuellen Speichergrößen kaum ins Gewicht fallen würde)

    was wäre die unordered map?
    wie gesagt, ich will in die Struktur eine Ini-datei laden/rekonstruieren

    Gruß Frank



  • frank schrieb:

    wenn ich den Sectionnamen bei jedem Item hinterlege (map< string, map<string, string> > ) habe ich einen massiven speicherverbrauch (auch wenn das bei aktuellen Speichergrößen kaum ins Gewicht fallen würde)

    Da vertust Du Dich massiv bzgl "massiven Speicherverbrauch". Der Sectionsname würde in der Datenstruktur nur 1mal pro Sektion gespeichert.

    Vor einem Jahr habe ich das auch mal per map<string,map<string,string> > gemacht. Im Nachhinein stellte ich aber fest, dass "Ini" zu wenig hierarchisch ist und ich tiefere Ebenen "frickeln" musste. Hätte ich mal lieber XML verwenden sollen...



  • typedef std::string Key;
    typedef std::string Value;
    typedef std::string SectionKey;
    typedef std::map<Key, Value> Section;
    typedef std::map<SectionKey, Section> IniFile;
    

    Ich würde aber überlegen das in einer Klasse zu kapseln, um die Zugriffe etwas lesbarer zu machen.



  • ah, jetzt seh ichs auch, dass der sectionname nur einmal gespeichert wird 🙂

    ich baue dass schon in eine Klasse, alleine schon wegen der parsing-routinen

    auf den ersten Blick macht das construct map<string,map<string,string>> das ganze einfacher, besonders, weil ich mir die zuordnung der section zu einer index-variable spare

    nur wie muss der äußere interator aussehen?
    der innere bleibt ja bei "std::map<std::string, std::string>::iterator value_iter;"...nur der äußere müsste als 2.Element eine map beinhalten.

    //edit:

    folgendes compiliert ohne Fehler...ist es auch richtig?

    //g++ -Wall inifile.cpp -o inifile
    
    # include <string> //cpp-string
    
    #include <map> //for config
    
    using namespace std;
    
    typedef std::string IniKey;
    typedef std::string IniValue;
    typedef std::string IniSectionKey;
    typedef std::map<IniKey, IniValue> IniSection;
    typedef std::map<IniSectionKey, IniSection> IniFile;
    
    int main(int argc, char *argv[])
    {
      IniFile ini;
      //std::map<std::string,std::string>
      std::map<std::string, IniSection>::iterator section_iter;
      std::map<std::string, std::string>::iterator value_iter;
      for (section_iter = ini.begin(); section_iter != ini.end(); section_iter++) 
      {
        std::string section_name=section_iter->first;
        IniSection section=section_iter->second;
        for (value_iter = section.begin(); value_iter != section.end(); value_iter++) 
        {
          std::string value_name=value_iter->first;
          std::string value_value=value_iter->second;
        }
      }
    }
    


  • Hallo,

    ich habe es mittlerweile soweit, dass das parsing der Datei funktioniert, aber etweder wird nichts hinzugefügt, oder das auslesen ist falsch...

    hier mal mein Code:

    typedef std::string tIniKey;
    typedef std::string tIniValue;
    typedef std::string tIniSectionKey;
    
    typedef std::map<tIniKey, tIniValue> tIniSection;
    typedef std::map<tIniSectionKey, tIniSection> tIniFile;
    
    std::map<std::string, tIniSection>::iterator section_iter;
    std::map<std::string, std::string>::iterator value_iter;
    
    //private der klasse:
    tIniSection fSection;
    
    //zuweisung in methode
    fSection=fIniFile[section];
    fSection[key]=value;
    
    //auslesen in anderer methode
      for (section_iter = fIniFile.begin(); section_iter != fIniFile.end(); section_iter++)
      {
        fSection=section_iter->second;
        for (value_iter = fSection.begin(); value_iter != fSection.end(); value_iter++) 
        {
          cout << "[Section]:" << section_iter->first << "Key:" << value_iter->first.c_str() << ",Value:" << value_iter->second.c_str() << endl;
        }
      }
    

    sieht jemand den Fehler? für mich scheint alles zu passen

    so wie es aussieht, wird die Section erstellt, aber die untermap nicht (oder sie wird irgendwo wieder freigegeben)

    ich habe den kompletten code mal hier hochgeladen: http://nopaste.info/6e393da13f.html

    Gruß Frank



  • Wir wärs mit boost::multi_index ?



  • möchte ungern fremde libs verwenden, wenn die funktionalität durch die STL verfügbar ist.

    wenn ich ein neues Item so anlege, funktioniert es:

    fIniFile[section][key]=value;
    

    in hinblick auf case-insensitive Zugriffe und Vermeidung von doppelten Sections/Keys, möchte ich aber nach der section suchen, ggf. erstellen und falls sie existiert hat, den key suchen.

    das geht als Einzeiler nach der Schreibweise oben nicht.



  • Hallo,

    ich habe es hinbekommen...ich suche nach der Section/dem Key case-insensitive und nutze den vorhandenen Namen (wenn existiert, sonst den parameter) um den Wert zu setzen.

    void SetValue(string section,string key,string value)
    
        {
    
          section=trim(section);
    
          key=trim(key);
    
          value=trim(value);
    
          string existing_section=section_find(section);
    
          if (existing_section=="")
    
          { //section does not exist
    
            fIniFile[section][key]=value;
    
          } else
    
          {
    
            string existing_key=key_find(section,key);
    
            if (existing_key == "")
    
            { //key does not exist in existing section
    
              fIniFile[existing_section][key]=value;
    
            } else
    
              fIniFile[existing_section][existing_key]=value;
    
          }
    
        }
    

    somit ist meine INI-Klasse soweit komplett. Sie ist mit ca. 300 Zeilen recht klein und funktioniert unter linux und windows...man muss nur die entsprechende fileexists-Funktion aktivieren.

    Wer interesse hat...ich habe sie unter http://www.fw-web.de/download.php?file=cpp/inifile.cpp hochgeladen

    Gruß Frank


Anmelden zum Antworten