2013-06-30 6 views
6

I haben eine Struktur, die 3 Felder, zwei int s (nennen wir sie A und B ) und eine bool(C).Triple-Karte einschließlich 2 Schlüssel

Ich möchte eine Art von Array dieser Struktur erstellen und in der Lage sein, über einen der Schlüssel (A oder B) darauf zuzugreifen, um das Lochobjekt (mit A, B und C) zurückzugeben. Ich werde nicht so etwas wie "das ganze Objekt, für das der Bool wahr ist" bekommen, wenn das einen Unterschied macht.

Offensichtlich sind beide Schlüssel einzigartig und das Bool kann nicht sein, aber ich dachte, ich würde es aus Gründen der Klarheit erwähnen.

Wenn es kein A oder B gab, wäre es ein einfaches std::map<int, bool>.

Die einzige Lösung, die ich derzeit sehe, ist ein Wrapper mit 2 set s und einem vector. Gibt es eine Möglichkeit, mein Leben einfacher zu machen?

Hinweis: Es enthält höchstens hundert Tupel, daher sollte die Leistung kein Problem sein. Linearer Zugriff ist akzeptabel.

Um es noch deutlicher, hier zu machen ist, was ich zu tun in der Lage sein möchte:

foobar<int, int, bool> array; // or something along those lines 

array.add(1, 101, true); 
array.add(2, 102, false); 

array.getA(1); // returns first object 
array.getA(2); // returns second object 
array.getB(102); // returns second object again 
+0

Wenn dies Ihre reale Anforderung (int, int, bool) und kein Kürzel Beispiel ist, würde ich es nur mit zwei Karten ('map '), eins für A und eins für B tun. –

+0

Es ist ein schnitt beispiel, aber am wichtigsten wäre diese lösung ne einen Wrapper sowieso, um die 2 'bool's synchron zu halten. – 1ace

Antwort

6

Ich glaube, was Sie suchen, ist boost::multi_index. Damit können Sie einen Container mit mehreren Indizes deklarieren.

struct MultiIDStruct 
{ 
    size_t idA; 
    size_t idB; 
    std::string name; 
}; 

namespace mul = boost::multi_index; 

boost::multi_index_container< MultiIDStruct, 
    mul::indexed_by< 
     mul::ordered_unique< mul::member< MultiIDStruct, size_t, &MultiIDStruct::idA > >, 
     mul::ordered_unique< mul::member< MultiIDStruct, size_t, &MultiIDStruct::idB > > 
    > > data; 

(Used-Namespace „Abkürzung“, wie pro Rapptz Vorschlag)

Denn hier Beispiel wird ein multi_index Behälter von MultiIDStruct, für die es zwei einzigartige Ordnungen, eine auf idA (das ist ein Mitglied von MultiIDStruct) und eine zweite auf idB (die auch ein Mitglied ist).

Die Template-Parameter scheinen auf den ersten Blick eine Handvoll zu sein, aber sie sind nicht so schlecht, wenn Sie einmal verstanden haben, wie sie funktionieren.

+2

Sie können dies verkürzen, indem Sie 'namespace mul = boost :: multi_index' oder so etwas tun. – Rapptz

+0

Das sieht perfekt aus. Ich werde es mir morgen genauer ansehen und entscheiden, ob ich dies oder die Lösung von RyanMcK bevorzuge. – 1ace

0

Ich weiß, dass ich nicht das Detail Umsetzung gegeben habe. Aber ich schlage nur eine Logik mit zwei Karten vor. Was stimmt damit nicht? Warum werde ich downvoted?

struct s 
{ 
int i; 
int j; 
bool b; 
}; 

std::map<int, int> mapA; 
std::map<int, s> mapB; 

const s& getA(int i) 
{ 
    return mapB[mapA[i]]; 
} 

const s& getB(int j) 
{ 
    return mapB[j]; 
} 

void add(int i, int j, bool b) 
{ 
    s p; 
    p.i=i; 
    p.j=j; 
    p.b=b; 
    mapB[j]=p; 
    mapA[i]=j; 
} 
+0

Ich bin kein Downwoter, aber Sie können nicht das ganze Objekt für 'b' Schlüssel bekommen. – soon

+0

@soon Was ist "Lochobjekt"? – Immueggpain

+0

Es war ein Tippfehler. Ganzes Objekt. – soon

1

Der Vorschlag, es in zwei Karten aufgeteilt ist sicherlich etwas einfacher, aber wenn man etwas mehr Flexibilität wünschen und C++ 11 für Funktionen wie std::tuple verwenden können, könnten Sie etwas von der Form versuchen:

#include <iostream> 
#include <map> 
#include <tuple> 

template <typename T1, typename T2, typename T3> 
class foobar 
{ 
public: 
    void add(T1 t1, T2 t2, T3 t3) 
    { 
     m1[t1] = std::make_tuple(t1, t2, t3); 
     m2[t2] = std::make_tuple(t1, t2, t3); 
    } 

    std::tuple<T1,T2,T3> getA(T1 t1) 
    { 
     return m1[t1]; 
    } 

    std::tuple<T1,T2,T3> getB(T2 t2) 
    { 
     return m2[t2]; 
    } 

private: 
    std::map<T1,std::tuple<T1,T2,T3>> m1; 
    std::map<T2,std::tuple<T1,T2,T3>> m2; 
}; 

int main() 
{ 
    foobar<int, int, bool> array; // or something along those lines 

    array.add(1, 101, true); 
    array.add(2, 102, false); 

    auto res1 = array.getA(1); // returns first object 
    auto res2 = array.getA(2); // returns second object 
    auto res3 = array.getB(102); // returns second object again 

    std::cout << std::get<0>(res1) << std::endl; 
    std::cout << std::get<1>(res2) << std::endl; 
    std::cout << std::get<2>(res3) << std::endl; 

    return 0; 
} 

A working example gibt den Ausgang 1, 102, 0 (falsch).

+0

Nun, das ist ziemlich genau der Wrapper, an den ich gedacht habe, obwohl ich denke, dass es viel größer wäre. Vielen Dank! – 1ace

0

Mit dem gleichen Problem, und eine andere Lösung!

Haben Sie zwei Hash-Funktionen auf A und B, geben Sie h1 (A) und h2 (B) so, dass sie nicht die gleichen Werte geben.Beispiel:

uint32_t A; 
uint32_t B; 

uint64_t hashA(uint32_t value) 
{ return ((uint64_t)value) << 32; } 

uint64_t hashB(uint32_t value) 
{ return (uint64_t)value; } 

Setzen Sie alle Ihre Sachen in std :: map, so dass Hasha und hashB den gleichen Wert für Bool haben. Greifen Sie darauf entweder mit hashA oder hashB zu.

Beispiel: A = 0x10000001, B = 0x20000002, C = true

Hasha (A): 0x1000000100000000 hashB (B): 0x0000000020000002

Karte: 0x1000000100000000 -> true 0x0000000020000002 -> true

Verwandte Themen