2013-06-30 14 views
6

ho una struttura contenente 3 campi, due int s (chiamiamoli A e B) ed un bool(C).mappa Triple tra cui 2 chiavi

Voglio creare una sorta di matrice di quella struttura ed essere in grado di accedervi tramite uno qualsiasi dei tasti (A o B), ottenendo in cambio l'oggetto foro (con A, B e C). Non avrò bisogno di fare qualcosa del tipo "ottenere tutto l'oggetto per il quale il bool è vero", se questo fa alcuna differenza.

Ovviamente, entrambe le chiavi sono uniche e il bool non può essere, ma ho pensato di parlarne per motivi di chiarezza.

Se non c'era A o B, sarebbe un semplice std::map<int, bool>.

L'unica soluzione che attualmente vedo è quella di creare un wrapper contenente 2 set s e uno vector. C'è un modo per semplificarmi la vita?

NB: Conterrà al massimo un centinaio di tuple, quindi le prestazioni non dovrebbero essere un problema. L'accesso lineare è accettabile.

Per rendere ancora più chiaro, qui è quello che mi piacerebbe essere in grado di fare:

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

Se questo è il tuo reale requisito (int, int, bool) e non un esempio ridotto, lo farei semplicemente con due mappe ('mappa '), una per A e una per B. –

+0

È un esempio ridotto, ma soprattutto questa soluzione non sarebbe ha comunque un wrapper per mantenere sincronizzati i 2 'bool's. – 1ace

risposta

6

Credo che quello che stai cercando è boost::multi_index. Ti consentirà di dichiarare un contenitore con più indici.

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; 

(namespace Usato "scorciatoia" come da Rapptz suggerimento)

Per esempio qui si ha una multi_index contenitore MultiIDStruct per i quali vi sono due ordinamenti unici, uno su idA (che è un membro di MultiIDStruct) e un secondo su idB (che è anche un membro).

I parametri del modello sembrano una manciata all'inizio, ma non sono così male una volta capito come funzionano.

+2

Puoi accorciarlo facendo 'namespace mul = boost :: multi_index' o qualcosa del genere. – Rapptz

+0

Questo sembra perfetto. Ne avrò uno sguardo più approfondito domani e deciderò se preferisco questa o la soluzione di RyanMcK. – 1ace

0

lo so non ho dato l'implementazione dettagli. Ma sto solo suggerendo una logica con due mappe. Che cosa c'è che non va? Perché ottengo 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

Non sono un downwoter, ma non è possibile ottenere l'intero oggetto per la chiave 'b'. – soon

+0

@soon cosa è "oggetto buco"? – Immueggpain

+0

Era un errore di battitura. Oggetto intero – soon

1

La proposta di dividerlo in due mappe è certamente un po 'più semplice, ma se si vuole un po' di flessibilità e possibile utilizzare C++ 11 per caratteristiche come std::tuple, si potrebbe provare qualcosa di forma:

#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 fornisce l'uscita 1, 102, 0 (falso).

+0

Beh, questo è più o meno il wrapper che avevo in mente, anche se pensavo che sarebbe stato molto più grande. Grazie! – 1ace

0

Avere lo stesso problema e una soluzione diversa!

Hanno due funzioni di hash su A e B, dando h1 (A) e h2 (B) tali, che non danno valori uguali.Esempio:

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; } 

Inserisci tutte le tue cose in std :: map in modo che hashA e hashB abbiano lo stesso valore per bool. Accedilo con hashA o hashB.

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

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

mappa: 0x1000000100000000 -> true 0x0000000020000002 -> true