【问题标题】:How can I create my own comparator for a map?如何为地图创建自己的比较器?
【发布时间】:2011-08-09 15:33:23
【问题描述】:
typedef map<string, string> myMap;

当向myMap 插入一个新的pair 时,它将使用键string 来通过它自己的字符串比较器进行比较。是否可以覆盖该比较器?例如,我想通过长度而不是字母来比较键 string。或者还有其他方法可以对地图进行排序吗?

【问题讨论】:

    标签: c++ stl stdmap


    【解决方案1】:

    std::map 最多接受四个模板类型参数,第三个是比较器。例如:

    struct cmpByStringLength {
        bool operator()(const std::string& a, const std::string& b) const {
            return a.length() < b.length();
        }
    };
    
    // ...
    std::map<std::string, std::string, cmpByStringLength> myMap;
    

    或者,您也可以将比较器传递给maps constructor

    但是请注意,当按长度进行比较时,地图中每个长度只能有一个字符串作为键。

    【讨论】:

    • 请注意,如果我们想包含重复的键,我们可以使用 multimap
    • @GeorgFritzsche 你有没有机会提供一个将比较器传递给构造函数的例子?
    • @bpeikes:看起来并没有太大的不同:std::map&lt;std::string, std::string&gt; myMap(cmpByStringLength());
    • 我遇到了 std::map 的问题,有些是递增顺序,有些是递减顺序。我不想使用 std::map 和 std::map 因为那样我就不能使用按不同顺序排序的地图作为单个函数的参数,除非我将所有内容都设为模板。我发现我必须执行以下操作: typedef std::map mymap;然后我能够传递函数。我尝试了以下方法,但它不起作用: typedef std::map mymap; mymap map1(std::less); mymap map2(std::greater);
    • @GeorgFritzsche:这不适用于将比较器传递给构造函数,因为构造函数参数必须是比较器类型的实例,而cmpByStringLength 不是std::less&lt;std::string&gt; 的实例。对于可以在构造函数中设置任何比较器的通用地图,您需要类似 std::map&lt;std::string, std::string, std::function&lt;bool(const std::string &amp;, const std::string &amp;)&gt;&gt; myMap(cmpByStringLength);
    【解决方案2】:

    由于C++11,您也可以使用lambda expression 而不是定义比较器结构:

    auto comp = [](const string& a, const string& b) { return a.length() < b.length(); };
    map<string, string, decltype(comp)> my_map(comp);
    
    my_map["1"]      = "a";
    my_map["three"]  = "b";
    my_map["two"]    = "c";
    my_map["fouuur"] = "d";
    
    for(auto const &kv : my_map)
        cout << kv.first << endl;
    

    输出:

    1
    两个

    呵呵

    我想重复一下 Georg 回答的最后一点:按长度比较时,地图中每个长度只能有一个字符串作为键。

    Code on Ideone

    【讨论】:

      【解决方案3】:

      是的,map 上的第三个模板参数指定了比较器,它是一个二元谓词。示例:

      struct ByLength : public std::binary_function<string, string, bool>
      {
          bool operator()(const string& lhs, const string& rhs) const
          {
              return lhs.length() < rhs.length();
          }
      };
      
      int main()
      {
          typedef map<string, string, ByLength> lenmap;
          lenmap mymap;
      
          mymap["one"] = "one";
          mymap["a"] = "a";
          mymap["fewbahr"] = "foobar";
      
          for( lenmap::const_iterator it = mymap.begin(), end = mymap.end(); it != end; ++it )
              cout << it->first << "\n";
      }
      

      【讨论】:

      • 为什么派生自std::binary_function?需要吗?
      • std::binary_function 在 c++17 中被删除,所以这个答案可能会使用更新。
      【解决方案4】:

      将指向您的比较函数的指针的类型指定为映射中的第 3 种类型,并将函数指针提供给映射构造函数:
      map&lt;keyType, valueType, typeOfPointerToFunction&gt; mapName(pointerToComparisonFunction);

      请看下面的示例,它为map 提供比较函数,vector 迭代器作为键,int 作为值。

      #include "headers.h"
      
      bool int_vector_iter_comp(const vector<int>::iterator iter1, const vector<int>::iterator iter2) {
          return *iter1 < *iter2;
      }
      
      int main() {
          // Without providing custom comparison function
          map<vector<int>::iterator, int> default_comparison;
      
          // Providing custom comparison function
          // Basic version
          map<vector<int>::iterator, int,
              bool (*)(const vector<int>::iterator iter1, const vector<int>::iterator iter2)>
              basic(int_vector_iter_comp);
      
          // use decltype
          map<vector<int>::iterator, int, decltype(int_vector_iter_comp)*> with_decltype(&int_vector_iter_comp);
      
          // Use type alias or using
          typedef bool my_predicate(const vector<int>::iterator iter1, const vector<int>::iterator iter2);
          map<vector<int>::iterator, int, my_predicate*> with_typedef(&int_vector_iter_comp);
      
          using my_predicate_pointer_type = bool (*)(const vector<int>::iterator iter1, const vector<int>::iterator iter2);
          map<vector<int>::iterator, int, my_predicate_pointer_type> with_using(&int_vector_iter_comp);
      
      
          // Testing 
          vector<int> v = {1, 2, 3};
      
          default_comparison.insert(pair<vector<int>::iterator, int>({v.end(), 0}));
          default_comparison.insert(pair<vector<int>::iterator, int>({v.begin(), 0}));
          default_comparison.insert(pair<vector<int>::iterator, int>({v.begin(), 1}));
          default_comparison.insert(pair<vector<int>::iterator, int>({v.begin() + 1, 1}));
      
          cout << "size: " << default_comparison.size() << endl;
          for (auto& p : default_comparison) {
              cout << *(p.first) << ": " << p.second << endl;
          }
      
          basic.insert(pair<vector<int>::iterator, int>({v.end(), 0}));
          basic.insert(pair<vector<int>::iterator, int>({v.begin(), 0}));
          basic.insert(pair<vector<int>::iterator, int>({v.begin(), 1}));
          basic.insert(pair<vector<int>::iterator, int>({v.begin() + 1, 1}));
      
          cout << "size: " << basic.size() << endl;
          for (auto& p : basic) {
              cout << *(p.first) << ": " << p.second << endl;
          }
      
          with_decltype.insert(pair<vector<int>::iterator, int>({v.end(), 0}));
          with_decltype.insert(pair<vector<int>::iterator, int>({v.begin(), 0}));
          with_decltype.insert(pair<vector<int>::iterator, int>({v.begin(), 1}));
          with_decltype.insert(pair<vector<int>::iterator, int>({v.begin() + 1, 1}));
      
          cout << "size: " << with_decltype.size() << endl;
          for (auto& p : with_decltype) {
              cout << *(p.first) << ": " << p.second << endl;
          }
      
          with_typedef.insert(pair<vector<int>::iterator, int>({v.end(), 0}));
          with_typedef.insert(pair<vector<int>::iterator, int>({v.begin(), 0}));
          with_typedef.insert(pair<vector<int>::iterator, int>({v.begin(), 1}));
          with_typedef.insert(pair<vector<int>::iterator, int>({v.begin() + 1, 1}));
      
          cout << "size: " << with_typedef.size() << endl;
          for (auto& p : with_typedef) {
              cout << *(p.first) << ": " << p.second << endl;
          }
      }
      

      【讨论】:

      • 这个decltype(int_vector_iter_comp)* 太棒了!谢谢!!
      猜你喜欢
      • 2018-05-16
      • 1970-01-01
      • 2011-01-31
      • 1970-01-01
      • 1970-01-01
      • 2014-10-25
      • 1970-01-01
      • 2018-08-19
      • 1970-01-01
      相关资源
      最近更新 更多