-1

How can I use a vector of variants as the key in unordered_map?

For example, I'd like to make the following code work.

using VariantType = std::variant<int, std::string, unsigned int>;
using VecVariantType = std::vector<VariantType>;
std::unordered_map<VecVariantType, int, $some_hash_function$> m;

How do I implement $some_hash_function$?

dalibocai
  • 2,289
  • 5
  • 29
  • 45
  • Suggestion: [If a question](https://stackoverflow.com/questions/63607075/how-to-use-variants-as-the-key-in-unordered-map) is unclear, or is not [mre], posting it again without modifications is not a good idea. – Mansoor Aug 27 '20 at 16:33
  • Are you sure you need such a map? It doesn't make any sense. What would be an example of mapping a vector of variants to an int? – Vlad Feinstein Aug 27 '20 at 16:35
  • 1
    Isn't this essentially the same question you asked yesterday? https://stackoverflow.com/questions/63607075/how-to-use-variants-as-the-key-in-unordered-map – Retired Ninja Aug 27 '20 at 16:37
  • @RetiredNinja Yesterday's question basically had a mistake in it. The code sample left out the `vector` and the question was answered without the `vector` before it was corrected. Since the answer was correct, I reverted the question and recommended that it be asked again with the `vector`. – user4581301 Aug 27 '20 at 17:03
  • @Mansoor same as above. The question in both cases lacks MRE, but since the asker knows this and knows what they have won't work, this should be clear enough. Yes, it's probably still an XY Question, using a `vector` of `variant` as a mapping key is most likely a poor design decision with a much simpler alternative, but the goal in the question is clear. At least to me it's clear. Good idea, probably not. – user4581301 Aug 27 '20 at 17:07
  • @Mansoor I took user4581301's suggestion and asked a new question, as my previous one had a mistake. – dalibocai Aug 27 '20 at 17:47
  • @VladFeinstein I'd like to implement a GroupBy operation for a table, where the type of the columns cannot be determined during compilation. The groupby key could involve multiple columns. If you have a good idea to implement it without using a vector of variants as the key, I'm all ears. – dalibocai Aug 27 '20 at 17:49

1 Answers1

2

I enjoy a good terrible idea...

I have no idea how or why you would use something like this for something other than a "I wonder if I can get this to compile and run" example.

#include <iostream>
#include <vector>
#include <unordered_map>
#include <variant>

using VariantType = std::variant<int, std::string, unsigned int>;
using VecVariantType = std::vector<VariantType>;

struct Hasher
{
    size_t operator()(const VecVariantType &v) const
    {
        size_t hash = 0;
        for (auto &val : v)
        {
            hash ^= std::hash<VariantType>()(val);
        }
        return hash;
    }
};

std::ostream& operator<<(std::ostream& out, std::pair<const VecVariantType, int> &p)
{
    out << "key: { ";
    bool needs_comma = false;
    for (auto &var : p.first)
    {
        if (needs_comma)
        {
            out << ", ";
        }
        if (std::holds_alternative<int>(var))
        {
            out << "int: " << std::get<int>(var);
            needs_comma = true;
        }
        if (std::holds_alternative<std::string>(var))
        {
            out << "string: " << std::get<std::string>(var);
            needs_comma = true;
        }
        if (std::holds_alternative<unsigned int>(var))
        {
            out << "uint: " << std::get<unsigned int>(var);
            needs_comma = true;
        }
    }
    out << " }, value: " << p.second;
    return out;
}

void lookup(const VecVariantType &var, std::unordered_map<VecVariantType, int, Hasher> &m)
{
    std::cout << "Lookup ";
    auto it = m.find(var);
    if (it != m.end())
    {
        std::cout << "success - " << *it << "\n";
    }
    else
    {
        std::cout << "failure\n";
    }
}

int main()
{
    std::unordered_map<VecVariantType, int, Hasher> m;
    auto one = VecVariantType { 1, "one", 1u };
    auto two = VecVariantType { 2, "two", 2u };
    auto three = VecVariantType { 3, "three", 3u };
    auto nnn = VecVariantType { 1, "one", 1u, 2, "two", 2u, 3, "three", 3u };
    m.emplace(one, 1);
    m.emplace(two, 2);
    m.emplace(three, 3);
    m.emplace(nnn, 999);

    std::cout << "Enumerating:\n";
    for (auto& item : m)
    {
        std::cout << "    " << item << "\n";
    }

    lookup(one, m);
    lookup(two, m);
    lookup(three, m);
    lookup(nnn, m);
}

https://repl.it/repls/AmazingCrushingOpen64

Retired Ninja
  • 4,785
  • 3
  • 25
  • 35