std::set oder was?



  • Guten Abend allerseits.

    Ich brauche hier einen assoziativen Container, dessen Elemente den Schlüssel (konkret als std::string) selbst bereitstellen, jedoch nicht selber Schlüssel sind. Nachher will ich per Schlüssel auf die Elemente zugreifen:

    container<Type> foo;
    foo.insert(someType); // someType stellt den Schlüssel bereit.
    

    foo["key"] soll mir Type & zurückgeben. Wie mach ich das? Mit std::set scheint es nicht zu funktionieren; std::map ist nicht besonders elegant weil die Schlüssel dann mehrfach vorkommen und ich diese überhaupt explizit übergeben muss.



  • Du könntest std::set mit einem eigenen Vergleichskriterium verwenden, das auf diesen Schlüsseln basiert. (set hat allerdings keinen operator[], also müsstest du ihn selber nachbauen)



  • Du meinst ich soll dieses "less" implementieren (wollte ich sowieso) und danach eine Klasse von set vererben und dort operator[] überladen? Wie jedoch komme ich dann vom Schlüssel wieder zum Wert? Hier liegt mein Problem...



  • Hi,

    ich habe das Anliegen noch nicht ganz verstanden: Du willst WAS ablegen ?

    Call0r schrieb:

    ...
    Ich brauche hier einen assoziativen Container, dessen Elemente den Schlüssel ... selbst bereitstellen, jedoch nicht selber Schlüssel sind....

    (theoretisch können "Container Schlüssel sein", aber das ist hier wohl auch nicht gemeint).

    Meinst Du sowas:

    struct myComp {
       bool operator()(pair<string, Type> const& lhs, pair<string, Type> const& rhs) {
          return lhs.first < rhs.first;
       }
    };
    
    set<pair<string, Type>, myComp > Container;
    

    ?
    Da sehe ich aber keinen besonderen Vorteil ggü. einer map und

    Call0r schrieb:

    ...std::map ist nicht besonders elegant weil die Schlüssel dann mehrfach vorkommen ...

    Das ist (zumindestens bzgl. dem mir bekannten Begriff "Schlüssel") falsch.

    Gruß,

    Simon2.



  • Okay ich versuchs nochmals zu beschreiben 😉
    Ich habe z.B. folgende Klasse:

    class foo
    {
    public:
        std::string name() const; // das soll der Schlüssel sein.
    };
    

    Nun will ich diese Objekte in einem Container ablegen...

    container<foo> bar;
    bar.insert(some_foo);
    

    Schliesslich will ich die Objekte im Container über den Schlüssel ansprechen à la

    bar[key]->name() == key; // das soll die bedingung sein
    


  • Hier scheint es das zu geben was ich suche, jedoch ist das für .NET und momentan kann ich .NET nicht wirklich gebrauchen http://msdn2.microsoft.com/de-de/library/ms132439



  • Wie Simon2 schon angedeutet hat, kannst du einfach einen eigenen Comparator nehmen:

    struct foo_cmp
    {
      bool operator()( foo const& lhs, foo const& rhs ) const
      {
        return lhs.get_key() < rhs.get_key();
      }
    };
    

    Du brauchst aber ein Objekt um nach Elementen zu suchen - im Zweifelsfall schreib dir einfach ein make_dummy_foo( std::string const& with_key ) .

    Ist allerdings echt nicht allzu elegant, von daher solltest du vielleicht lieber eine std::map adaptieren.



  • Nach dem was ich jetzt gehört habe werde ich den Comparator schreiben und ihn in einer von set-abgeleiteten Klasse benutzen. Subscripting kann ich ja dann per binärer Suche machen. 💡



  • Wenn du auf das Objekt zugreifen willst(mit einem Schlüssel als String) dann solltest du doch eine map benutzen!

    Ich glaube nämlich, dass du set mit multimap verwechselt. schau dir mal std::set std::multiset std::map und std::multimap an!

    Hoffe das hilft 😉



  • megaweber schrieb:

    Wenn du auf das Objekt zugreifen willst(mit einem Schlüssel als String) dann solltest du doch eine map benutzen!...

    Ich würde das zwar auch immer erstmal "als Default" versuchen, aber soooo exotisch ist es nicht, dass Klassen in "Identifizierende" und "Daten" zerfallen.

    Modellierung1

    struct Person {
       string Name, Vorname, Adresse;
       bool maennlich;
       unsigned int Schuhgroesse;
    };
    
    struct Person_NameAdress_Comp {
       bool operator<(Person const& lhs, Person const& rhs) {
          return // ... hier Name, Vorname, Adresse vergleichen
       }
    };
    
    set<Person, Person_NameAdress_Comp> PersonenRegister;
    

    Modellierung2

    struct Person_ID {
       string Name, Vorname, Adresse;
    };
    
    struct Person_Daten {
       bool maennlich;
       unsigned int Schuhgroesse;
    };
    
    struct Person_ID_Comp {
       bool operator<(Person_ID const& lhs, Person_ID const& rhs) {
          return // ... hier Name, Vorname, Adresse vergleichen
       }
    };
    
    map<Person_ID, Person_Daten, Person_NameAdress_Comp> PersonenRegister;
    

    Welchen Weg man wählt, muss man anhand der Aufgabenstellung entscheiden. Wenn z.B. Personen ein "starkes Eigenleben" haben, liegt IMO erstmal der erste Weg näher. Wenn dagegen "Personen" (oder evtl. "PersonDBEinträge") im Wesentlichen in ihrem Register "leben", dann wählt man vielleicht besser den zweiten.

    Gruß,

    Simon2.


Anmelden zum Antworten