【问题标题】:Creating C++ map from composite key从复合键创建 C++ 映射
【发布时间】:2012-10-18 06:09:45
【问题描述】:

我想创建一个包含复合键的映射。例如,我有学生的姓名和他/她正在学习的学期。现在我想创建一个地图,让卷号和学期一起作为地图的键。

【问题讨论】:

    标签: c++ map


    【解决方案1】:

    编辑: 有一瞬间的疑问让我想知道 operator==() 是否也必须由键类型提供,因为显然在 map 中查找值时,必须进行相等性测试在引擎盖下使用。但是 2003 C++ 标准中的 23.1.2/3 表示没有必要:需要通过检查 a < bb < a 是否为假来确定两个关键对象 ab 之间的相等性。 :)

    #include <map>
    
    struct key {
        int rollNo;
        int semester;
        string whateverElse;
    
        // Provide a "<" operator that orders keys.
        // The way it orders them doesn't matter, all that matters is that
        // it orders them consistently.
        bool operator<(key const& other) const {
            if (rollNo < other.rollNo) return true; else
            if (rollNo == other.rollNo) {
                if (semester < other.semester) return true; else
                if (semester == other.semester) {
                    if (whateverElse < other.whateverElse) return true;
                }
            }
    
            return false;
        }
    };
    
    std::map<key, whateverValueTypeYouWant> dictionary;
    

    【讨论】:

    • 你可以写if(a&lt;b) return true; if(a&gt;b) return false;,那么你就不需要嵌套ifs了。
    • @ybungalobill:好主意,但我建议将if (b&lt;a) return false; 用于第二部分,以便所有比较都通过operator&lt;() 进行。
    • @j_random_hacker: 甚至更简单 => boost::tie(this-&gt;rollNo, this-&gt;semester, this-&gt;whateverElse) &lt; boost::tie(other.rollNo, other.semester, other.whateverElse);,元组默认具有字典顺序;)
    【解决方案2】:

    与其为键定义自己的类并且必须定义自己的比较运算符,因为您只关心卷号和学期,我会使用 std::pair。

    #include <utility>
    #include <map>
    
    // This maps an std::pair of (roll number, semester) to a StudentRecord.
    std::map<std::pair<int, int>, StudentRecord> studentMap;
    
    studentMap.insert(std::pair<std::pair<int, int>, StudentRecord>(std::make_pair(100, 100), StudentRecord());
    

    如果您对卷号和学期使用的不是 int 值,您可以轻松地使用这对中的值。请记住,如果您为这些对象使用自定义结构,它们将需要实现相等和比较运算符,在这种情况下,您将失去使用一对而不是直接使用其他结构的好处。

    【讨论】:

    • 这是一个更好、更通用的答案,因为 std::pair 已经有了必要的比较器
    • 充实@pwned 的评论:如果TU 都可以通过&lt; 进行比较,那么std::pair&lt;T, U&gt; 类型将自动通过&lt; 进行比较,这是您最自动化的无论如何都可以希望:)
    • @pwned 如果需要更多字段进行比较,它会迅速变得丑陋。幸好 C+11 有std::tuple
    • 如果您确实需要更多字段进行比较,那么自定义结构绝对是要走的路。但是,鉴于 OP 说卷号和学期为学生定义了一个唯一的自然键,因此键中似乎不太可能需要更多字段。
    【解决方案3】:

    std::map 键需要实现 operator

    #include <map>
    struct Student
    {
      Student(int roll_no, int semestre)
      : roll_no(roll_no), semestre(semestre)
      {}
      int roll_no;
      int semestre;
      bool operator< (Student const &s) const
      {
        return semestre* 100000+ roll_no< s.semestre* 100000+ s.roll_no;
      }
    };
    
    #include <iostream>
    #include <ostream>
    
    int main()
    {
      std::map<Student, int> m;
      m[Student(1, 1)]= 42;
      m[Student(1, 2)]= 43;
      std::cout<< m[Student(1, 1)];
    }
    

    【讨论】:

    • 我认为 OP 希望 Student 成为映射类型,并使用 Student 数据作为单独的键。
    • OP:semestre 乘以 100000 的效果是允许使用单个整数比较来完成比较。如果您确定 roll_no 永远不会超过 99999,这是一种方便的技术。
    • @j_random_hacker 这正是我想要展示的。而且我的老板在我身上,所以我必须尽快完成:D
    【解决方案4】:

    您可以定义一个包含 roll_no 和学期成员的结构类型。

            struct stu_key
            {   
                int roll_no;
                int semester;
    
                bool operator <(const stu_key &sk) const
                {   
                   //compare roll_no and semester 
                }   
            };
    
            std::map<stu_key , value_type> stu_map;
    

    【讨论】:

    • operator&lt;() 需要标记为const,它的参数也是如此。
    • @j_random_hacker 是的,我已经改变了。
    • +1,但最好去掉typedef 并将参数调用operator&lt;() 简单地const stu_key &amp;sk。您不需要 struct 关键字或 C++ 中的 typedef struct ... 解决方法。
    猜你喜欢
    • 1970-01-01
    • 2017-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-28
    • 2019-04-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多