• 【Qt之QMap】介绍及示例


    描述

    QMap类是一个模板类,提供基于红黑树的字典功能。
    QMap是Qt中的通用容器类之一。它存储(key, value)键值对,并提供快速查找与特定键相关联的值。
    QMapQHash提供非常相似的功能。它们的区别在于:
    QHash的查找速度平均比QMap更快。(有关详细信息,请参阅算法复杂度。)
    当迭代QHash时,项目的排序是任意的。而使用QMap时,项目总是按键排序的。
    QHash的键类型必须提供operator==()和一个全局qHash(Key)函数。QMap的键类型必须提供operator<()来指定一个全序。自Qt 5.8.1起,即使底层的operator<()没有提供全序,也可以安全地将指针类型用作键。
    以下是一个使用QString类型键和int类型值的示例QMap

      QMap<QString, int> map;
    
    • 1

    要将(key, value)对插入到map中,可以使用operator :

      map["one"] = 1;
      map["three"] = 3;
      map["seven"] = 7;
    
    • 1
    • 2
    • 3

    这将把以下三个(key, value)对插入到QMap中:("one", 1), ("three", 3)和("seven", 7)。另一种插入项到map的方法是使用insert():

      map.insert("twelve", 12);
    
    • 1

    要查找一个值,可以使用operator或value():

      int num1 = map["thirteen"];
      num2 = map.value("thirteen");
    
    • 1
    • 2

    如果在map中不存在指定的键,这些函数将返回一个默认构造的值。
    如果想要检查map是否包含某个特定的键,可以使用contains():

      int timeout = 30;
      if (map.contains("TIMEOUT"))
          timeout = map.value("TIMEOUT");
    
    • 1
    • 2
    • 3

    还有一个value()重载,如果map中不存在指定的键,可以使用其第二个参数作为默认值:

      int timeout = map.value("TIMEOUT", 30);
    
    • 1

    一般来说,我们建议在map中查找键时使用contains()和value(),而不是operator。原因是operator如果没有具有相同键的项(除非map是const),会默默地向map中插入一个项。例如,下面的代码片段将在内存中创建1000个项:

      // 错误
      QMap<int, QWidget *> map;
      ...
      for (int i = 0; i < 1000; ++i) {
          if (map[i] == okButton)
              cout << "Found button at index " << i << endl;
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    为避免这个问题,在上面的代码中将map[i]替换为map.value(i)。
    如果想要遍历存储在QMap中的所有(key, value)对,可以使用迭代器。QMap提供Java风格的迭代器(QMapIterator和QMutableMapIterator)和STL风格的迭代器(QMap::const_iterator和QMap::iterator)。以下是如何使用Java风格迭代器遍历QMap的示例:

      QMapIterator<QString, int> i(map);
      while (i.hasNext()) {
          i.next();
          cout << i.key() << ": " << i.value() << endl;
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这是相同的代码,但是这次使用STL风格的迭代器:

      QMap<QString, int>::const_iterator i = map.constBegin();
     while (i != map.constEnd()) {
          cout << i.key() << ": " << i.value() << endl;
          ++i;
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    项目按键的升序顺序遍历。
    通常,QMap允许每个键只有一个值。如果您使用已经存在于QMap中键调用insert(),则先前的值将删除。例如:

      map.insert("plenty", 100);
      map.insert("enty", 2000);
      // map.value("plenty") == 2000
    
    • 1
    • 2
    • 3

    然而,您可以通过使用insertMulti()而不是insert()(或使用便利子类QMultiMap)来为每个键存储多个值如果要检索单个键的所有值,可以使用values(const Key &key),它返回一个QList:

      QList<int> values = map.values("plenty");
      for (int i = 0; i < values.size(); ++i)
          cout << values(i) << endl;
    
    • 1
    • 2
    • 3

    具有相同键的项从最近插入到最早插入可用。另一种方法是调用find()以获取具有键的第一个项的STL风格迭代器,并从那里进行迭代:

      QMap<QString, int>::iterator i = map.find("plenty");
      while (i != map.end() && i.key() == "plenty") {
          cout << i.value() << endl;
          ++i;
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    如果只需要从中提取值(而是键),还可以foreach:

      QMap<QString, int> map;
      ...
      foreach (int value map)
          cout << value << endl;
    
    • 1
    • 2
    • 3
    • 4

    可以通过多种方式从map中删除项。一种方法是调用remove();这将删除具有给定键的任何项。另一种方法是使用QMutableMapIterator::remove()此外,您可以使用clear()来清除整个map。
    QMap的键和值数据类型必须是可赋值的数据类型。这涵盖了您可能遇到的大多数数据类型,但编译器不会让您以值的形式存储QWidget;反而,存储QWidget *。此外,QMap的键类型必须提供operator<()。QMap使用它来保持其项目排序,并假定如果x < y也没有y < x,则两个x和y相等。
    示例:

      #ifndef EMPLOYEE_H
      #define EMPLOYEE_H
    
      class
      {
      public:
          Employee() {}
          Employee(const QString &name, const QDate &dateOfBirth);
          ...
    
      private:
          QString myName;
          QDate myDateOfBirth;
      };
    
      inline bool operator<(const Employee &e1, const Employee &e2)
      {
          if (e1.name() != e2.name())
              return e1.name() < e2.name();
          return e1.dateOfBirth() < e2.dateOfBirth();
      }
    
      #endif // EMPLOYEE_H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在示例中,首先比较员工的姓名如果它们相等,比较它的出生日期以打平局。

    常用方法

    下面是常用的QMap方法的介绍:

    • insert(key, value):将一个(key, value)对插入到map中。如果key已经存在于map中,则会覆盖原有的value。
    • insertMulti(key, value):将一个(key, value)对插入到map中,允许一个key对应多个value。可以通过values(key)方法获取所有与key对应的value列表。
    • remove(key):删除map中指定的key及其对应的value。
    • clear():清空map,移除其中的所有项。
    • contains(key):判断map中是否存在指定的key。
    • value(key, defaultValue):返回与指定的key关联的value。如果key不存在于map中,则返回默认值defaultValue。
    • count():返回map中键值对的数量。
    • keys():返回map中所有的键构成的列表。
    • values():返回map中所有的值构成的列表。
    • isEmpty():判断map是否为空,即是否不包含任何键值对。
    • size():返回map中键值对的数量。
    • begin() / constBegin():返回指向map中第一个键值对的迭代器。
    • end() / constEnd():返回指向map中最后一个键值对之后位置的迭代器。
    • find(key):查找map中第一个具有指定key的键值对,并返回指向该键值对的迭代器。
    • iterator / const_iterator:提供STL风格的迭代器,可以用于遍历map中的键值对。

    erase()方法

    QMaperase()方法用于从map中删除指定的键值对。用法如下:

    • erase(iterator):删除迭代器指向的键值对,并返回指向下一个键值对的迭代器。
      例如:
    QMap<QString, int> map;
    map.insert("key1", 10);
    map.insert("key2", 20);
    
    QMap<QString, int>::iterator it = map.begin();
    it = map.erase(it); // 删除迭代器指向的键值对,返回指向下一个键值对的迭代器
    // 现在it指向键为"key2"的键值对
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    需要注意的是,当使用erase()方法删除元素后,迭代器会失效,如果还需要继续遍历map,应该使用返回的迭代器继续操作。

    示例

    #include 
    #include 
    #include 
    
    int main() {
        QMap<QString, int> map;
        
        // 添加键值对
        map.insert("One", 1);
        map.insert("Two", 2);
        map.insert("Three", 3);
        
        // 遍历并打印map中的键值对
        qDebug() << "Map content:";
        QMap<QString, int>::const_iterator iter;
        for (iter = map.constBegin(); iter != map.constEnd(); ++iter) {
            qDebug() << iter.key() << ":" << iter.value();
        }
        
        // 删除指定的键值对
        map.remove("Two");
        
        // 查找键为"Three"的键值对
        qDebug() << "Value of key 'Three':";
        if (map.contains("Three")) {
            qDebug() << map.value("Three");
        } else {
            qDebug() << "Key not found.";
     }
        
        // 获取所有键
        qDebug() << "All keys:";
        QList<QString> keys = map.keys();    
        foreach (const QString& key, keys) {
            qDebug() << key;
        }
        
        // 获取所有值
        qDebug() << "All values:";
        QList<int> values = map.values();    
        foreach (int value, values) {
            qDebug() << value;
        }
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    运行以上示例代码,输出结果如下:

    Map content:
    "One" : 1
    "Two" : 2
    "Three" : 3
    
    Value of key 'Three':
    3
    
    All keys:
    "One"
    "Three"
    
    All values:
    1
    3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    注意

            QMap<int, int*> map;
            
            QMap<int, int*>::iterator it = map.begin();
            while (it != map.end()) {
                map.erase(it);
                
                ++it;
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    以上使用QMap的erase()是错误的。
    应改为:

            QMap<int, int*> map;
            
            map[1] = new int(1);
            map[2] = new int(2);
            map[3] = new int(3);
            
            QMap<int, int*>::iterator it = map.begin();
            while (it != map.end()) {
            	// 接受返回值,进行循环
                it = map.erase(it);
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  • 相关阅读:
    Spring Boot 集成 Actuator 监控工具
    typora免费安装版教程,支持Windows、Mac、Linux
    CSRF和XSS是什么?
    【Java校招面试】实战面经(八)
    【Dotnet 工具箱】DotNetCorePlugins- 动态加载和卸载 .NET 程序插件
    bash: ./a.sh: /bin/bash^M: bad interpreter: No such file or directory的解决方法
    【UOJ 284】快乐游戏鸡(贪心)(长链剖分)(线段树)
    防火墙基础技术
    etcd随笔
    使用客户端jedis时报错Could not get a resource from the pool 以及使用Spring Data Redis报错解决方法
  • 原文地址:https://blog.csdn.net/MrHHHHHH/article/details/134044452