1

How to check for equality of two std::unordered_map using std::equal to check if both containers have same keys and their corresponding key values. Below my code prints unequal even though both containers have same size, set of keys and the corresponding key values are equal.

#include <iostream>
#include <unordered_map>

int main() {
    std::unordered_map<char, int> um1, um2;
    um1['f'] = 1;
    um1['o'] = 1;
    um1['r'] = 1;

    um2['o'] = 1;
    um2['r'] = 1;
    um2['f'] = 1;

    if (um1.size() == um2.size() && std::equal(um1.begin(), um1.end(), um2.begin()))
        std::cout << "equal" << std::endl;
    else
        std::cout << "unequal" << std::endl;
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302
Harry
  • 2,177
  • 1
  • 19
  • 33
  • 3
    `If (um1 == um2)`? – NathanOliver Dec 02 '21 at 15:13
  • 4
    keep in mind that is is an **unordered** map, so the order in which the iterators will iterate the keys is unspecified and can be seemingly random. This would work with a `std::map`, since it will sort it's elements in a consistent way. But `std::unordered_map` is implemented as a hashmap, so the order in which you will get the elements depends on the hash function, bucket size and insertion order. (it might also change down the line if a rehashing occurs) – Turtlefight Dec 02 '21 at 15:14
  • Refer to this- https://www.cplusplus.com/reference/unordered_map/unordered_map/operators/ – Abdur Rakib Dec 02 '21 at 15:15
  • @NathanOliver it's giving me the required output. Does this work for any insertion order? – Harry Dec 02 '21 at 15:19
  • [`unordered_map::operator ==`](https://en.cppreference.com/w/cpp/container/unordered_map/operator_cmp). – Jarod42 Dec 02 '21 at 15:19
  • 2
    @Harry operator== will work for any insertion order. keep in mind however that comparing two unordered_maps can be a lot more expensive than comparing two normal maps (due to their unsorted nature) - comparing `std::map`s will be at most `O(n)` while comparing `std::unsorted_map`s can be up to `O(n²)`. (with n being the number of elements in the map) – Turtlefight Dec 02 '21 at 15:21
  • It should still be O(n) to iterate over an unordered_map, right? https://stackoverflow.com/questions/25195233/time-complexity-of-iterating-through-a-c-unordered-map Then you have two O(1) lookups for the values to compare, which is a constant multiplier. – Kenny Ostrom Dec 02 '21 at 15:53
  • What you should have done is pretty well covered in comments. I posted on why std::equal doesn't do what you expected. – Kenny Ostrom Dec 02 '21 at 15:55
  • @KennyOstrom the gotcha is that the equality function and hash function for the unordered_map's might be different from the normal comparison function for the contained objects. [example godbolt](https://godbolt.org/z/Y37nM6fTE) So you can't use the `O(1)` lookup but rather have to rely on `equal_range()` and check if the groups you get from each container are permutations of each other (which is rather expensive to do). This is also documented on the [`std::unordered_map::operator== page`](https://en.cppreference.com/w/cpp/container/unordered_map/operator_cmp) – Turtlefight Dec 02 '21 at 17:14
  • Oh, right, worst case. Okay, fair point, but the average case is O(N). – Kenny Ostrom Dec 02 '21 at 23:37

1 Answers1

2

https://en.cppreference.com/w/cpp/algorithm/equal

Two ranges are considered equal if they have the same number of elements and, for every iterator i in the range [first1,last1), *i equals *(first2 + (i - first1)).

Consider this code added to your code snippet:

for (auto it : um1)
    std::cout << it.first << ": " << it.second << std::endl;
std::cout << std::endl;
for (auto it : um2)
    std::cout << it.first << ": " << it.second << std::endl;

f: 1
o: 1
r: 1

o: 1
r: 1
f: 1

Note that the iteration happens in a different order, as you should expect. Therefore they are not std::equal because (as documented above) that expects the same values in the same order.

However, this specitic container has its own operator== as noted in the comments, which checks for value equality as you were originally expecting for this specific container.

Kenny Ostrom
  • 5,639
  • 2
  • 21
  • 30