如何在C++中有效地比较两个字符串映射

lin*_*llo 32 c++ comparison maps stl std

我想知道是否只应用一些标准算法就可以编写一个比较两个的短函数,std::map<string, string>如果所有键值(但是有些)都为真,则返回true.

例如,这两个地图应该被评估为相等

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";
Run Code Online (Sandbox Code Playgroud)

假设两个映射具有相同的大小,并且除了由键"X"和键"Y"存储的值之外,它们的所有元素必须成对比较.第一次尝试将是一个非常低效的双嵌套for循环.我相信可以实现更好的解决方案.

Seb*_*ach 72

我不确定你究竟在寻找什么,所以让我首先给出完全平等,然后是关键平等.也许后者已经满足你的需求.

完全平等

可以使用std::mapstd::equalstd::operator==s 测试完全相等:

#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";
}
Run Code Online (Sandbox Code Playgroud)

关键平等

C++ 2003

基于上面的代码,我们可以为std::pair调用添加一个谓词:

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";
}
Run Code Online (Sandbox Code Playgroud)

C++(C++ 11)

使用新的lambda表达式,您可以这样做:

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);
}
Run Code Online (Sandbox Code Playgroud)

C++(C++ 14)

新增2014-03-12

使用新的通用lambda表达式,您可以这样做:

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);
}
Run Code Online (Sandbox Code Playgroud)

作为样式,您还可以直接将C++ 11和C++ 14中的lambda表达式作为参数内联:

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; });
}
Run Code Online (Sandbox Code Playgroud)

  • 如果我错了,请纠正我,但这不是比较地图的有效方法。建议的比较是类似矢量的比较。我的意思是成员(成对)可能会以不同的顺序排列,但地图将是相同的。 (2认同)
  • 基于 `std::equal` 的解决方案不能用于无序容器(`std::unordered_map`、`std::unordered_set` 等)。为了更好的安全性,“key_compare”模板应包含相应的“static_assert”,以确保它只能与允许的容器一起使用。否则很容易做出无效代码。 (2认同)