1

I have a use case wherein I have to get a value from a map, given a key. Now the key can be ID (integer) or Name (string).

I thought about the following structure

map1 :- ID -> value

map2 :- Name -> ID

And hide this structure under a common abstraction, so that either name or ID can be used to retrieve the value.

Is there a better way to do this?

Vaibhav Gupta
  • 89
  • 1
  • 6
  • 2
    Is there a 1-1 relation you could calculate from Integer-ID-key to String-Name-ID-Key? I guess not, so you wouldn't really need the second map. I think the idea is good, but keep in mind to manage both maps in a valid manner, so if in map 1 an ID gets removed, what do you want to do with map 2? Delete the entry? Then you have to iterate over the values, leave it there and do not touch it? Could lead to unused memory and maybe double entries. Depending on that, implement your idea – RoQuOTriX Jul 09 '20 at 06:09
  • 1
    Please read [how to ask](https://stackoverflow.com/help/how-to-ask), before posting. – Geno C Jul 09 '20 at 06:09
  • Consider using struct { int id, string name } as key for the map. Idea on how to implement this can be taken from here: https://stackoverflow.com/questions/7204283/how-can-i-use-a-struct-as-key-in-a-stdmap – tsvedas Jul 09 '20 at 06:23
  • @TomasŠvedas I thought about `std::pair` as well but how will you find an entry if you have given only ID or only name? – Scheff's Cat Jul 09 '20 at 07:23
  • 1
    Just make the == operator check for first.id == second.id || first.name == second.name – tsvedas Jul 09 '20 at 07:24
  • @TomasŠvedas For a map, you need a less predicate. I tried to imagine one but it felt horrible somehow. So, I probably would prefer what OP suggested (incl. the detail to wrap both maps into a new class to manage them synchronously). – Scheff's Cat Jul 09 '20 at 07:25
  • @Scheff I'm coming from C# background, thus didn't really thought about the '<' operator... I could probably come up with a solution after doing some more research... Maybe using hash for strings less predicate could help here... Just a thought. – tsvedas Jul 09 '20 at 07:31

1 Answers1

3

Have a look at boost::multi_index. It allows you to make containers with any combination of lookup that you want.

struct item
{
    int ID;
    std::string Name;
    value_t Value;
};

namespace bmi = boost::multi_index;
using map_t = bmi::multi_index_container<item, bmi::indexed_by<
    bmi::unordered_unique<bmi::tag<struct ID>, bmi::member<item, int, &item::ID>>,
    bmi::unordered_unique<bmi::tag<struct Name>, bmi::member<item, std::string, &item::Name>>
>>;

map_t Map;
/* add some values */
auto idIt = Map.get<ID>().find(1); // lookup by ID
auto nameIt = Map.get<Name>().find("Vaibhav Gupta"); // lookup by Name
Caleth
  • 52,200
  • 2
  • 44
  • 75