46

I'm wondering if only by applying some standard algorithms is possible to write a short function which compares two std::map<string, string> and returns true if all the key-value (but some) pairs are true.

For example, these two maps should be evaluated as equal

map<string,string> m1, m2;

m1["A"]="1";
m2["A"]="1";

m1["B"]="2";
m2["B"]="2";

m1["X"]="30";
m2["X"]="340";

m1["Y"]="53";
m2["Y"]="0";

Suppose that the two maps have same size and all their elements must be pairwise compared except the value stored by the key "X" and key "Y". A first attempt would be a very inefficient double nested for loop.

I'm sure a better solution can be achieved.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
linello
  • 8,451
  • 18
  • 63
  • 109
  • 3
    Your definition of what it means for two maps to be equivalent (not equal) is ambiguous. What do you mean all but some? How many should there at least be, one? – Paul Manta Dec 12 '11 at 10:42
  • By equal do you mean "the same number of elements and the same keys, ignoring the values"? – hmjd Dec 12 '11 at 10:43
  • 1
    If you want to check if the two maps are completely equal, == should be sufficient. – Sebastian Dec 12 '11 at 10:46
  • Excuse me, I wasn't very clear. Suppose the two maps have N elements, but I want to compare only M < N elements and return true if all the M elements are equal, in other words I want to ignore those N-M elements. In the example N=4, M=2 ( i want to return true because the values associated to keys "A" and "B" are equal in both `m1` and `m2` A templatized solution is welcome... – linello Dec 12 '11 at 10:47
  • @Als, has stated using `std::equal` in which you can specify the range of elements to check so this should suffice. – hmjd Dec 12 '11 at 10:49

3 Answers3

104

I am not sure what exactly you are looking for, so let me first give complete equality and then key equality. Maybe the latter fits your needs already.

Complete Equality

(While standard equivalence can be tested using std::map's own comparison operators, the following can be used as a base for a comparison on a per-value basis.)

Complete equality can be tested using std::equal and std::operator== for std::pairs:

#include <utility>
#include <algorithm>
#include <string>
#include <iostream>
#include <map>

template <typename Map>
bool map_compare (Map const &lhs, Map const &rhs) {
    // No predicate needed because there is operator== for pairs already.
    return lhs.size() == rhs.size()
        && std::equal(lhs.begin(), lhs.end(),
                      rhs.begin());
}

int main () {
    using namespace std;

    map<string,string> a, b;

    a["Foo"] = "0";
    a["Bar"] = "1";
    a["Frob"] = "2";

    b["Foo"] = "0";
    b["Bar"] = "1";
    b["Frob"] = "2";

    cout << "a == b? " << map_compare (a,b) << " (should be 1)\n";
    b["Foo"] = "1";
    cout << "a == b? " << map_compare (a,b) << " (should be 0)\n";

    map<string,string> c;
    cout << "a == c? " << map_compare (a,c)  << " (should be 0)\n";
}

Key Equality

C++2003

Based on the above code, we can add a predicate to the std::equal call:

struct Pair_First_Equal {
    template <typename Pair>
    bool operator() (Pair const &lhs, Pair const &rhs) const {
        return lhs.first == rhs.first;
    }
};

template <typename Map>
bool key_compare (Map const &lhs, Map const &rhs) {
    return lhs.size() == rhs.size()
        && std::equal(lhs.begin(), lhs.end(),
                      rhs.begin(),
                      Pair_First_Equal()); // predicate instance
}

int main () {
    using namespace std;

    map<string,string> a, b;

    a["Foo"] = "0";
    a["Bar"] = "1";
    a["Frob"] = "2";

    b["Foo"] = "0";
    b["Bar"] = "1";
    b["Frob"] = "2";

    cout << "a == b? " << key_compare (a,b) << " (should be 1)\n";
    b["Foo"] = "1";
    cout << "a == b? " << key_compare (a,b) << " (should be 1)\n";

    map<string,string> c;
    cout << "a == c? " << key_compare (a,c)  << " (should be 0)\n";
}

C++ (C++11)

Using the new lambda expressions, you can do this:

template <typename Map>
bool key_compare (Map const &lhs, Map const &rhs) {

    auto pred = [] (decltype(*lhs.begin()) a, decltype(a) b)
                   { return a.first == b.first; };

    return lhs.size() == rhs.size()
        && std::equal(lhs.begin(), lhs.end(), rhs.begin(), pred);
}

C++ (C++14)

added 2014-03-12

Using the new generic lambda expressions, you can do this:

template <typename Map>
bool key_compare (Map const &lhs, Map const &rhs) {

    auto pred = [] (auto a, auto b)
                   { return a.first == b.first; };

    return lhs.size() == rhs.size()
        && std::equal(lhs.begin(), lhs.end(), rhs.begin(), pred);
}

As a style-matter, you can also inline the lambda expressions in C++11 and C++14 directly as a parameter:

bool key_compare (Map const &lhs, Map const &rhs) {
    return lhs.size() == rhs.size()
        && std::equal(lhs.begin(), lhs.end(), rhs.begin(), 
                      [] (auto a, auto b) { return a.first == b.first; });
}
Sebastian Mach
  • 38,570
  • 8
  • 95
  • 130
  • and maybe also a key-value equality, by comparing `lhs.second == rhs.second` This is a very complete answer, thank you! – linello Dec 12 '11 at 11:35
  • One can also use the `std::equal` variant that checks automatically that the two maps have the same length. – NOhs Jul 11 '17 at 10:08
  • 2
    Correct me if I'm wrong but that's not a valid way to compare maps. Advised comparison is vector-like comparison. I mean that members (pairs) might go in different order but maps will be equal. – Andrew Feb 15 '19 at 20:32
  • @luizfls: Thanks for your edit https://stackoverflow.com/revisions/8473603/4, but it is not valid in this case, as the asker wanted to customize the comparison. Also, the code you removed served as a basis for the remainder of the answer - please read the question more carefully before attempting to edit existing answers. And please read the whole answer before editing. Just blindly bursting into fragments of text is not good at all. – Sebastian Mach Jul 26 '19 at 07:22
  • @SebastianMach You're welcome. The question is hard to understand as you pointed out in the first sentence of your answer. The first algorithm you presented works exactly the same as `==` so I thought it'd be better to use it. And I didn't break the linearity of the answer because I did read the whole answer before editing and made sure the linearity wasn't broken. – luizfls Jul 26 '19 at 19:38
  • 2
    `std::equal`-based solution cannot be used for unordered containers (`std::unordered_map`, `std::unordered_set` and so on). For better safety, `key_compare` template should contain corresponding `static_assert` to make sure that it may be used only with allowed containers. Otherwise, it is easy to make invalid code. – J. Doe Oct 21 '20 at 20:01
0

The answer is quiet simple we can directly compare two maps by equivalence relational operator("=="), just like we compare two variables.

#include<bits/stdc++.h>
using namespace std;
int main()
{
map<string,int> m1;
map<string,int> m2;

m1["str1"]=47;
m1["str2"]=87;

m2["str1"]=47;
m2["str2"]=87;

if(m1==m2)
cout<<"maps are equal"<<endl;
else
cout<<"maps are not equal"<<endl;   
}

Output: https://i.stack.imgur.com/MCmN4.png

-3

I think if you're trying to access two maps of equal size simultaneously then you should create iterators, and traverse both maps this way.

 map<char, int> :: iterator itr1, itr2;
 itr1=first.begin();
 itr2=last.begin();
 
 while(itr1!=first.end() && itr2!=last.end())
 {
     if(itr1->first!=itr2->first || itr1->second!=itr2->second)
     {
       cout<<"Error"<<endl;
     }
     else 
     {
       cout<<"Ok so far"<<endl;
     }
     itr1++;
     itr2++;
 }
cigien
  • 57,834
  • 11
  • 73
  • 112
  • 1
    A solution that prints out the name of the contributor can be considered as nothing but spam. Also, even though it is essentially correct, it gives nothing beyond the accepted answer. – zkoza Jul 23 '21 at 16:45
  • This is a very poor technical solution when there are standard algorithms available for this purpose. – cigien Sep 08 '21 at 02:51