2016-08-28 9 views
11

piszę test jednostka testowa Google i chcę, aby sprawdzić, czy treść w unordered_map<std::string, std::string> jest taka sama jak std::map<std::string, std::string>jak łatwo sprawdzić, czy std :: map i std :: unordered_map zawiera te same elementy

Nie sądzę, że std::equal będzie działać, ponieważ elementy w std::map są sortowane według kryterium. Kolejność nie jest ważna.

+0

Można dokonać iteracji na jednym lub drugim i sprawdzić, czy wartości dla każdego klucza są takie same. – Chris

+1

Czy używasz gmock? https://groups.google.com/forum/#! topic/googlemock/kz4tACpCBME UnorderedElementsAreArray będzie ładnie działać tutaj. – FDinoff

+0

@FDinoff Nope tylko test Google! Nigdy nie korzystałem jeszcze z Gmocka, ale twój komentarz jest interesujący! czy łatwo dołączyć Gmock do GTest? – Aminos

Odpowiedz

14

Nie sądzę, że istnieje lepszy sposób niż przechodzenie przez wszystkie elementy jednej mapy i sprawdzanie, czy są one obecne na drugiej mapie. Jeśli sprawdzisz również, czy ilość elementów jest taka sama, dowiesz się, czy mapy są całkowicie takie same.

Na przykład:

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; 
     }); 
} 
+0

Dodałem trzeci parametr do definicji szablonu (powyżej i do std :: map ;)) moja mapa std :: map używa niestandardowego programu do zarządzania, aby móc go skompilować. To działa ! testy są również przekazywane. Dziękuję Ci ! – Aminos

+1

Witam, Właśnie wprowadziłem niewielką poprawę, aby zapobiec niepotrzebnym kopiom kluczy i wartości. (Zmieniono linię "std :: all_of".) – michalsrb

+2

@Aminos: w takim przypadku należy pamiętać, że jeśli mapa i mapa nieuporządkowana używają różnych definicji "równych kluczy", to sprawdzanie, czy rozmiary są zgodne, a jedna jest podzbiorem drugi niekoniecznie wystarczy, aby sprawdzić, czy są one takie same. Na przykład załóżmy, że mapa zawiera klawisze 'X' i' Y', mapowana_maga zawiera klucze 'Y' i' Z', ale także uważa, że ​​'X' i' Y' są równe i dlatego zgłasza zarówno 'X' jak i' Y 'być obecnym. –

9

Można utworzyć unordered_map z map, a następnie porównać dwa unordered_map. I wzajemnie.

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) {} 
+2

Prawdopodobnie ma to znacznie większą złożoność niż próba ręcznego znalezienia każdego elementu na mapie. Niezła odpowiedź. – Vality

+2

W rzeczywistości zarówno ta, jak i zaakceptowana odpowiedź mają złożoność tego samego czasu: O (n). Jednak ta odpowiedź powoduje kilka przydziałów i kopii przechowywanych elementów. Przyjęta odpowiedź nie działa, działa wyłącznie na niezmiennych danych. – michalsrb

1

zadam oczywiste pytanie, ale to naprawdę zmienia wszystko:

jest pojęcie równości w map zgodny z pojęciem równości w unordered_map?

przykładu niekompatybilnych definicje:

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); 
} 

W ten (contrived) wypadku możemy mieć

  • map: (1, 2, 3) i (1, 3, 3)
  • unordered_map: (1, 2, 3) i (1, 2, 4)

i naiwny look-up będą zgłaszać, że map jest zawarty w unordered_map, ponieważ ponieważ oba mają ten sam rozmiar doprowadziłoby do błędnego wniosku, że są one równe.


Rozwiązanie jeśli kanoniczny pojęcie równości istnieje jest sprawdzenie, po każdym look-up, że wynik look-up jest faktycznie taka sama jak oryginał.

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; 
} 

Uwaga: to może być przepisany z std::all i pojedynczym logicznej wypowiedzi; to kwestia gustu, wolę ją rozbić.

Jeśli nie kanoniczny pojęcie równości istnieje, wtedy odwrotny look-up może zastąpić sprawdzenie równości:

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; 
} 

To oczywiście nieco droższe.

Powiązane problemy