Как легко проверить, содержит ли std:: map и std:: unordered_map те же элементы
Я пишу тест Google unit test, и я хочу проверить, совпадает ли содержимое unordered_map<std::string, std::string>
с std::map<std::string, std::string>
Я не думаю, что std::equal
будет работать, поскольку элементы в std::map
сортируются по критерию. Порядок не важен.
Ответы
Ответ 1
Я не думаю, что есть лучший способ, чем просто перебирать все элементы одной карты и проверять, присутствуют ли они на другой карте. Если вы также убедитесь, что количество элементов одинаково, вы узнаете, все ли карты одинаковы.
Например:
template<typename K, typename E>
bool maps_equal(const std::map<K, E> &map, const std::unordered_map<K, E> &unordered_map) {
return
map.size() == unordered_map.size() &&
std::all_of(map.cbegin(), map.cend(), [&](const std::pair<const K, E> &item) {
auto iter = unordered_map.find(item.first);
return iter != unordered_map.end() && iter->second == item.second;
});
}
Ответ 2
Вы можете создать unordered_map
с помощью map
, а затем сравнить два unordered_map
. И наоборот.
std::unordered_map<std::string, std::string> m1;
std::map<std::string, std::string> m2;
std::unordered_map<std::string, std::string> m3(m2.begin(), m2.end());
if (m1 == m3) {}
Ответ 3
Я задам очевидный вопрос, но он действительно меняет все:
Является ли понятие равенства в map
совместимым с понятием равенства в unordered_map
?
В качестве примера несовместимых определений:
struct Point3D { std::int32_t x, y, z };
struct MapLess {
bool operator()(Point3D const& left, Point3D const& right) const {
return std::tie(left.x, left.y) < std::tie(right.x, right.y);
}
};
bool operator==(Point3D const& left, Point3D const& right) {
return std::tie( left.x, left.z)
== std::tie(right.x, right.z);
}
В этом (надуманном) случае мы могли бы:
-
map
: (1, 2, 3)
и (1, 3, 3)
-
unordered_map
: (1, 2, 3)
и (1, 2, 4)
и наивный поиск сообщит, что map
включен в unordered_map
, который, поскольку оба они имеют одинаковый размер, приведут к ошибочному выводу, что они равны.
Решение, если существует каноническое понятие равенства, состоит в том, чтобы проверить после каждого поиска, что результат поиска фактически совпадает с исходным.
template <typename M1, typename M2>
bool equal(M1 const& left, M2 const& right) {
if (left.size() != right.size()) { return false; }
for (auto const& e: left) {
auto const it = right.find(e.first);
if (it == right.end()) { return false; }
if (it->first != e.first) { return false; }
if (it->second != e.second) { return false; }
}
return true;
}
Примечание: это можно было бы переписать с помощью std::all
и одного булевского выражения; это вопрос вкуса, я предпочитаю разбить его.
Если каноническое понятие равенства не существует, то обратный поиск может заменить проверку равенства:
template <typename M1, typename M2>
bool equal(M1 const& left, M2 const& right) {
if (left.size() != right.size()) { return false; }
for (auto e = left.begin(), end = left.end(); e != end; ++e) {
auto const it = right.find(e->first);
if (it != right.end()) { return false; }
if (left.find(it->first) != e) { return false; }
if (it->second != e->second) { return false; }
}
return true;
}
Это, конечно, немного дороже.