2013-06-30 9 views
6

I mają strukturę zawierającą 3 pola, dwa int s (nazwijmy ich i B) i bool(C).potrójny mapę łącznie 2 klucze

Chcę utworzyć rodzaj tablicy tej struktury i mieć do niej dostęp za pomocą dowolnego klawisza (A lub B), otrzymując w zamian obiekt z dziurą (z A, B i C). Nie będę musiał robić czegoś takiego jak "uzyskanie całego obiektu, dla którego jest prawdziwe", jeśli to robi jakąkolwiek różnicę.

Oczywiście, oba klucze są unikalne, a bool nie może być, ale myślałem, że wspomnę o tym dla jasności.

Jeśli nie było A lub B, byłby prosty std::map<int, bool>.

Jedyne rozwiązanie, które obecnie widzę, to utworzenie opakowania zawierającego 2 set s oraz vector. Czy istnieje sposób na ułatwienie mi życia?

Uwaga: będzie zawierał co najwyżej sto krotek, więc wydajność nie powinna stanowić problemu. Dostęp liniowy jest akceptowalny.

Aby jeszcze wyraźniej, tutaj jest to, co chciałbym być w stanie to zrobić:

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

Jeśli to jest twoje prawdziwe wymaganie (int, int, bool), a nie przytaczany przykład, zrobiłbym to z dwiema mapami ('map '), jedną dla A i jedną dla B. –

+0

To jest wyciąć przykład, ale co najważniejsze, to rozwiązanie byłoby ne ed wrapper i tak, aby utrzymać 2 'bool's zsynchronizowane. – 1ace

Odpowiedz

6

Uważam, że to, czego szukasz, to boost::multi_index. Pozwoli to zadeklarować kontener z wieloma indeksami.

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; 

(Używany namespace „skrót”, jak za Rapptz sugestią)

Na przykład tutaj masz multi_index pojemnik MultiIDStruct dla których istnieją dwie unikalne uporządkowania, jeden na idA (który jest członkiem z MultiIDStruct) i drugą na idB (która jest także członkiem).

Parametry szablonu wydają się początkowo garść, ale nie są takie złe, gdy zrozumiesz, jak działają.

+2

Możesz to skrócić, wykonując 'namespace mul = boost :: multi_index' lub coś podobnego. – Rapptz

+0

To wygląda idealnie. Przyjrzę się temu jutro bardziej dogłębnie i zdecyduję, czy wolę to, czy też rozwiązanie RyanMcK. – 1ace

0

wiem, że nie daje wdrożenie szczegółowości. Ale sugeruję tylko logikę z dwiema mapami. Co jest z tym nie tak? Dlaczego dostaję obniżone głosy?

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

Nie jestem downwoter, ale nie można uzyskać całego obiektu dla klawisza 'b'. – soon

+0

@soon co to jest "obiekt dziury"? – Immueggpain

+0

To był literówka. Cały obiekt. – soon

1

Sugestia, aby podzielić go na dwie mapy z pewnością jest nieco prostsze, ale jeśli chcesz trochę więcej elastyczności i mogą korzystać z C++ 11 dla funkcji, takich jak std::tuple, można spróbować czegoś w postaci:

#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 podaje wynik 1, 102, 0 (fałsz).

+0

Cóż, to właściwie opakowanie, które miałem na myśli, chociaż byłbym znacznie większy. Dzięki! – 1ace

0

Mając ten sam problem i inne rozwiązanie!

Posiadają dwie funkcje mieszające na A i B, dając h1 (A) i h2 (B) takie, że nie dają równych wartości.Przykład:

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

Umieść wszystkie swoje rzeczy w std :: map, aby hashA i hashB miały tę samą wartość dla bool. Dostęp do niego za pomocą hashA lub hashB.

Przykład A = 0x10000001 B = 0x20000002 C = prawda

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

mapa 0x1000000100000000 -> prawda 0x0000000020000002 -> prawda