一、概述

QMap 是Qt的通用容器类之一。它存储(键,值) 对,并提供与键相关联的值的快速查找。其实就是一个键值对的集合,经常使用的。具体更详细还得看看帮助文档

QMap和QHash提供了非常相似的功能。区别在于:

  • QHash提供了比QMap更快的平均查找速度。
  • 在遍历QHash时,元素的顺序是任意的。在QMap中,元素总是按键排序了的。
  • QHash的键类型必须提供==() 运算符和一个全局的QHash (key) 函数。QMap的键类型必须提供<运算符来指定总顺序。由于Qt 5.8.1,使用指针类型作为键也是安全的,即使底层运算符<() 没有提供总的顺序。

二、使用

1. 初始化及属性

下面是一个QMap的例子,键为QString,值为int:

QMap<QString, int> map;

常用的函数:

  • size() :Map的大小
  • empty():是不是空
  • key():这个第一个元素的键
  • keys():返回所有的键
  • values():返回所有的值

2. 插入元素

要在map中插入一个(键,值) 对,可以使用 运算符:

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

这会将以下3个键值对插入到QMap中:(“one”, 1) 、(“three”, 3) 和(“seven”, 7) 。

另一种向map中插入元素的方法是使用insert() :

map.insert("twelve", 12) ;

通常,QMap每个键只允许一个值如果使用QMap中已经存在的键调用insert() ,之前的值将被删除。例如:

map.insert("plenty", 100) ;
map.insert("plenty", 2000) ;
// map.value("plenty")  == 2000

我们也可以使用insertMulti() 而不是insert() 来为每个键存储多个值(或者使用便捷的子类QMultiMap) 。如果想取得一个键对应的所有值,可以使用values(const key &key) ,它会返回一个QList:

QList<int> values = map.values("plenty") ;
for (int i = 0; i < values.size() ; ++i) 
	cout << values.at(i)  << Qt::endl;

共享相同键的项可以从最近插入到最近插入。另一种方法是调用find() 来获取第一个键对应的stl风格的迭代器,也就是说find() 返回的也是一个可迭代的对象,我们可以从那里开始迭代:

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

3. 查找值,获取值

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

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

如果在map中没有指定键的项,这些函数返回一个默认构造的值。就是这个键的构造函数,然后像int、double之类的就是0,QString 就是空字符串。

如果你想检查map中是否包含某个键,可以使用contains() :

int timeout = 30;
if (map.contains("TIMEOUT") ) 
	timeout = map.value("TIMEOUT") ;

还有一个value() 重载方法,如果指定的键不存在,则使用第二个参数作为默认值:

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

一般来说,我们推荐使用contains() 和value() 而不是 [ ] 在map中查找键。因为如果map中不存在键相同的元素,[ ]会静默地将元素插入到 map 中(除非map是const) 。有时候就要非常注意这个问题。例如,下面的代码片段将在内存中创建1000个元素:

// WRONG
QMap<int, QWidget *> map;
  ...
for (int i = 0; i < 1000; ++i)  {
	if (map[i] == okButton) 
		cout << "Found button at index " << i << Qt::endl;
}

为了避免这个问题,将上面代码中的map[i]替换为map.value(i) 。

4. 遍历键值对

如果想遍历存储在QMap中的所有键值对,可以使用迭代器。QMap提供了java风格的迭代器(QMapIterator和QMutableMapIterator) 和stl风格的迭代器(QMap::const_iterator和QMap::iterator) 。

下面是如何使用java风格的迭代器迭代QMap<QString, int>:

QMapIterator<QString, int> i(map) ;
while (i.hasNext() )  {
      i.next() ;
      cout << i.key()  << ": " << i.value()  << Qt::endl;
}

下面是相同的代码,但这次使用了stl风格的迭代器:

QMap<QString, int>::const_iterator i = map.constBegin() ;
while (i != map.constEnd() )  {
      cout << i.key()  << ": " << i.value()  << Qt::endl;
      ++i;
  }

每一个键值对 都是 按键升序遍历。

如果你只需要从map中提取值(而不是键) ,你也可以使用foreach:

QMap<QString, int> map;
  ...
foreach (int value, map) 
      cout << value << Qt::endl;

5. 删除元素

有几种方法可以从QMap中删除元素。
一种方法是调用remove() 方法;这将删除具有给定键的任何项。

另一种方法是使用QMutableMapIterator::remove() 。

此外,你可以使用clear() 清除整个QMap。

6. 注意

QMap的键和值数据类型必须是可分配的数据类型。这涵盖了您可能遇到的大多数数据类型,但是编译器不允许您将QWidget存储为值;相反,存储一个QWidget *。此外,QMap的键类型必须提供<运算符。QMap使用它来排序元素,如果x < y和y < x都不为真,则假设两个键x和y相等。
例子:

  #ifndef EMPLOYEE_H
  #define EMPLOYEE_H

  class Employee
  {
  public:
      Employee()  {}
      Employee(const QString &name, 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

在这个例子中,我们首先比较员工的名字。如果他们相等,我们比较他们的出生日期来打破平局。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐