3

when thinking about design decisions of my code regarding one-to-one relations I came to think about if I should use std::vector<std::pair<T1, T2>> instead of std::map<T1, T2>, and implement two methods A to B and B to A myself.

I can't use boost, so the answer to this question I found about it (One-to-one relation in STL terms) is not really fitting.

Is there some STL equivalent doing this job? Or do you think the vector is a bad idea? There won't be many entries in the struct ( < 10) but there will be a lot of access on it.

user3520616
  • 60
  • 3
  • 17
  • Which ways do you need associativity? Do you only want to look up a `T2` for any `T1` or also a `T1` for any `T2`? A single `std::map` and friends won't give you the latter. Also, if you are concerned about performance you will probably have to try out different options anyways. – Max Langhof Jan 28 '19 at 09:04
  • Yes the lookup will be both ways. I think the readability is important as well. It's a difficult decision, I think I'll stick with vector>.. – user3520616 Jan 28 '19 at 09:15
  • 1
    It will probably pay in the long run to wrap whatever you end up using in your own type. The STL has no pre-made solution for you, so writing your own class with defined semantics is cleaner (even if it does use the STL behind the scenes). – Max Langhof Jan 28 '19 at 09:19
  • 3
    With less than ten entries, even linear search should be quite fast. You should definitely wrap it, but the implementation can probably stay naive. The more efficient one or the one for more elements would largely depend on the types involved, how large they are (e.g. are those ints or 100kB structures), etc. – Bartek Banachewicz Jan 28 '19 at 09:27
  • Yes I've sticked to wrapping it in a class having two methods "toA(B)" and "toB(A)". If I gotta use it again I think I'll do a template-version of it. (The methods are just std::find_if over the vector inside) – user3520616 Jan 28 '19 at 09:37

2 Answers2

1

Try this:

#include <string>
#include <map>

template <typename MapA2B, typename MapB2A = std::map<MapA2B::mapped_type, MapA2B::key_type> >
MapB2A CreateInverseMap(const MapA2B& map)
{
    MapB2A ret;
    for (const MapA2B::value_type& value : map)
        ret[value.second] = value.first;
    return ret;
}

void Test()
{
    typedef std::map<int, std::string> A2B;
    A2B a2b =
    {
        { 1, "D" },
        { 2, "AA" },
        { 3, "CCC" },
    };
    typedef std::map<std::string, int> B2A;
    B2A b2a = CreateInverseMap(a2b);

    std::string b = a2b[2]; // b = "AA";
    int a = b2a["CCC"]; // a = 3;
}
guest
  • 11
  • 1
  • While this code may solve the question, [including an explanation](//meta.stackexchange.com/q/114762) of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please [edit] your answer to add explanations and give an indication of what limitations and assumptions apply. – Adrian Mole Oct 28 '22 at 11:15
0

I think in your case, you could try std::unordered_map<T1,T2> and std::unordered_map<T2,T1>. By using two unordered_map, you could do A2B and B2A both in O(1) time, which is faster than map or vector.

GuangshengZuo
  • 4,447
  • 21
  • 27
  • 1
    It's not necessarily faster. `unordered_map` is required to be implemented with buckets so it will basically look like `vector` which has bad cache locality. It can be faster depending on a lot of parameters but it doesn't have to... – sv90 Jan 28 '19 at 20:48