3

I have two elements (6 and 747) that share their key ("eggs"). I want to find all the elements that share a key (let's say "eggs", but I would in real life do that for every key). How to do that?

There must be a way to get a container or something back from the data structure . . .

gsamaras
  • 71,951
  • 46
  • 188
  • 305
  • In an unordered map you can't have the same key with different values, I don't really get the question... Are you asking how to check if the hash of multiple, different keys is the same and to output those buckets? Then krzaq's answer is correct. – Banex Nov 20 '16 at 23:30
  • I cannot accept it yet @Banex, time limit! Indeed I was confused, krzap helped though! Thanks! – gsamaras Nov 20 '16 at 23:31

2 Answers2

3

You're still mistaking key's value with key's hash. But to answer question as asked: you can use unordered_map's bucket() member function with bucket iterators:

std::unordered_map<int,int,dumbest_hash> m;
m[0] = 42;
m[1] = 43;

size_t bucket = m.bucket(1); 

for(auto it = m.begin(bucket), e = m.end(bucket); it != e; ++it) {
    cout << "bucket " << bucket << ": " << it->first << " -> " << it->second << '\n';
}

demo

In simple and mostly correct terms, unordered containers imitate their ordered counterparts in terms of interface. That means that if a map will not allow you to have duplicate keys, then neither will unordered_map.

unordered do employ hashing function to speed up the lookup, but if two keys have the same hash, they will not necessarily have the same value. To keep the behaviour similar to the ordered containers, unordered_set and unordered_map will only consider elements equal when they're actually equal (using operator== or provided comparator), not when their hashed values collide.

To put things in perspective, let's assume that "eggs" and "chicken" have the same hash value and that there's no equality checking. Then the following code would be "correct":

unordered_map<string, int> m;
m["eggs"] = 42;
m.insert(make_pair("chicken", 0)); // not inserted, key already exists
assert(m["chicken"] == 42);

But if you want allow duplicate keys in the same map, simply use unordered_multimap.

krzaq
  • 16,240
  • 4
  • 46
  • 61
  • What do you mean? Aren't 6 and 747 values and "eggs" their key? Ah you mean that the hashed value is not a value, nor a key, right? – gsamaras Nov 20 '16 at 23:25
  • hashed value is kind-of internal to the map. `"eggs"` is the key of your values, sure, but the map actually uses a numeric hash of it to speed things up. It's completely possible that another key, say `"chicken"` also yields the same hash (it will with the `dumbest_hash` from the example), but since they're not equal keys, they will not be treated as equal. You'll only notice performance loss. – krzaq Nov 20 '16 at 23:27
  • Yeah got it, thanks. However, now you are answering the give me the element that share a hash value, not a key (which is what I actually want, but didn't know), right? – gsamaras Nov 20 '16 at 23:29
  • 1
    Yes. If you want to allow multiple keys, just use `unordered_multimap` :) – krzaq Nov 20 '16 at 23:29
  • @gsamaras updated the answer a little, hopefully this will make it clearer, instead of being silly thoughtstream :) – krzaq Nov 20 '16 at 23:42
2

Unordered map does not have elements that share a key.

Unordered multi map does.

Use umm.equal_range(key) to get a pair of iterators describing the elements in the map that match a given key.

However, note that "collision" when talking about hashed containers usually refers to elements with the same hashed key, not the same key.

Also, consider using a unordered_map<key, std::vector<value>> instead of a multimap.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • 1
    Your last sentence gave me a spark. Why should I do that? Faster than a multimap? Can you point me somewhere to read about it? Or maybe that's a different question, so let's not cover it here?? – gsamaras Nov 20 '16 at 23:48
  • It's a good point. Afaik elements with duplicate hash value are kept in a linked list, but I'm not sure about the same key value in multimap. Still, you get to use `operator[]` and vector will be at least as efficient in almost any use case. – krzaq Nov 20 '16 at 23:51
  • @gsam iteration invalidation rules of unordered containers force key duplication and node based storage of key and value. The vector does not have the same guarantees, so it can skip key duplication and store values contiguously. Plus, I like `operator[]` on maps, and a map to vectors handles that. It is worth considering. – Yakk - Adam Nevraumont Nov 21 '16 at 00:07
  • @krzaq I see, interesting point guys! Here is a relevant question: [whats-the-advantage-of-multimap-over-map-of-vectors](http://stackoverflow.com/questions/4437862/whats-the-advantage-of-multimap-over-map-of-vectors). – gsamaras Nov 21 '16 at 12:33
  • @gsam map from key to variant of value and vector of value. ;) – Yakk - Adam Nevraumont Nov 21 '16 at 13:54
  • That sounds cool, but I am not sure I understand I follow Yakk, maybe my English. . . :/ – gsamaras Nov 21 '16 at 15:41
  • 1
    @gsamaras `std::unordered_map< Key, std::variant< Value, std::vector > >`; permits Key/Value pairs to exist, or a Key/List of Values. – Yakk - Adam Nevraumont Nov 21 '16 at 15:49