用for循环遍历QMap

我有一个QMap对象,我正在尝试将其内容写入一个文件。

 QMap<QString, QString> extensions; //.. for(auto e : extensions) { fout << e.first << "," << e.second << '\n'; } 

为什么我会得到: error: 'class QString' has no member named 'first' nor 'second'

是不是typesQPair

如果您想要firstsecond STL样式,请执行以下操作:

 for(auto e : extensions.toStdMap()) { fout << e.first << "," << e.second << '\n'; } 

如果您想使用Qt提供的function,请执行以下操作:

 for(auto e : extensions.keys()) { fout << e << "," << extensions.value(e) << '\n'; } 

C ++ 11基于范围的用于使用解除引用的迭代器的types作为自动推导的“游标”types。 这里是expression式*map.begin()的types。
而且,由于QMap::iterator::operator*()返回值(types为QString & )的引用,因此无法使用该方法访问该键。

你应该使用文档中描述的迭代器方法之一,但是你应该避免使用

  • keys()因为它涉及到创build一个键列表,然后search每个键的值,或者,
  • toStdMap()因为它将所有的地图元素复制到另一个地图元素,

这不会是最佳的。


你也可以使用一个包装来获得QMap::iterator作为autotypes:

 template<class Map> struct RangeWrapper { typedef typename Map::iterator MapIterator; Map &map; RangeWrapper(Map & map_) : map(map_) {} struct iterator { MapIterator mapIterator; iterator(const MapIterator &mapIterator_): mapIterator(mapIterator_) {} MapIterator operator*() { return mapIterator; } iterator & operator++() { ++mapIterator; return *this; } bool operator!=(const iterator & other) { return this->mapIterator != other.mapIterator; } }; iterator begin() { return map.begin(); } iterator end() { return map.end(); } }; // Function to be able to use automatic template type deduction template<class Map> RangeWrapper<Map> toRange(Map & map) { return RangeWrapper<Map>(map); } // Usage code QMap<QString, QString> extensions; ... for(auto e : toRange(extensions)) { fout << e.key() << "," << e.value() << '\n'; } 

这里还有一个包装。

对于对优化感兴趣的人,我尝试了几种方法,做了一些微观基准testing,我可以得出结论, STL风格的方法要快得多

我已经尝试用这些方法添加整数:

  • QMAP ::值()
  • Java风格迭代器(如文档中所build议的)
  • STL样式迭代器(也在文档中build议)

而且我将它与QList / QVector的求和整数进行了比较

结果:

 Reference vector : 244 ms Reference list : 1239 ms QMap::values() : 6504 ms Java style iterator : 6199 ms STL style iterator : 2343 ms 

代码感兴趣的人:

 #include <QDateTime> #include <QMap> #include <QVector> #include <QList> #include <QDebug> void testQMap(){ QMap<int, int> map; QVector<int> vec; QList<int> list; int nbIterations = 100; int size = 1000000; volatile int sum = 0; for(int i = 0; i<size; ++i){ int randomInt = qrand()%128; map[i] = randomInt; vec.append(randomInt); list.append(randomInt); } // Rererence vector/list qint64 start = QDateTime::currentMSecsSinceEpoch(); for(int i = 0; i<nbIterations; ++i){ sum = 0; for(int j : vec){ sum += j; } } qint64 end = QDateTime::currentMSecsSinceEpoch(); qDebug() << "Reference vector : \t" << (end-start) << " ms"; qint64 startList = QDateTime::currentMSecsSinceEpoch(); for(int i = 0; i<nbIterations; ++i){ sum = 0; for(int j : list){ sum += j; } } qint64 endList = QDateTime::currentMSecsSinceEpoch(); qDebug() << "Reference list : \t" << (endList-startList) << " ms"; // QMap::values() qint64 start0 = QDateTime::currentMSecsSinceEpoch(); for(int i = 0; i<nbIterations; ++i){ sum = 0; QList<int> values = map.values(); for(int k : values){ sum += k; } } qint64 end0 = QDateTime::currentMSecsSinceEpoch(); qDebug() << "QMap::values() : \t" << (end0-start0) << " ms"; // Java style iterator qint64 start1 = QDateTime::currentMSecsSinceEpoch(); for(int i = 0; i<nbIterations; ++i){ sum = 0; QMapIterator<int, int> it(map); while (it.hasNext()) { it.next(); sum += it.value(); } } qint64 end1 = QDateTime::currentMSecsSinceEpoch(); qDebug() << "Java style iterator : \t" << (end1-start1) << " ms"; // STL style iterator qint64 start2 = QDateTime::currentMSecsSinceEpoch(); for(int i = 0; i<nbIterations; ++i){ sum = 0; QMap<int, int>::const_iterator it = map.constBegin(); auto end = map.constEnd(); while (it != end) { sum += it.value(); ++it; } } qint64 end2 = QDateTime::currentMSecsSinceEpoch(); qDebug() << "STL style iterator : \t" << (end2-start2) << " ms"; qint64 start3 = QDateTime::currentMSecsSinceEpoch(); for(int i = 0; i<nbIterations; ++i){ sum = 0; auto end = map.cend(); for (auto it = map.cbegin(); it != end; ++it) { sum += it.value(); } } qint64 end3 = QDateTime::currentMSecsSinceEpoch(); qDebug() << "STL style iterator v2 : \t" << (end3-start3) << " ms"; } 

编辑七月2017年:我再次在我的新笔记本电脑(Qt 5.9,i7-7560U)上运行此代码,并得到了一些有趣的变化

 Reference vector : 155 ms Reference list : 157 ms QMap::values(): 1874 ms Java style iterator: 1156 ms STL style iterator: 1143 ms 

在这个基准testing中,STL风格和Java风格的performance非常相似

在“旧”C ++中,使用Qt,你可以这样做:

 QMap< QString, whatever > extensions; //... foreach( QString key, extensions.keys() ) { fout << key << "," << extensions.value( key ) << '\n'; } 

我没有一个C ++ 11编译器在这里,但也许下面的工作:

 for( auto key: extensions.keys() ) { fout << key << "," << extensions.value( key ) << '\n'; } 

您也可以使用迭代器,如果您喜欢使用它们,请检查hmuelners链接

QMap :: iterator使用key()和value() – 可以在Qt 4.8的文档或Qt-5的文档中find 。

编辑:

基于范围的for循环生成类似于此的代码(请参阅CPP参考 ):

 { for (auto __begin = extensions.begin(), __end = extensions.end(); __begin != __end; ++__begin) { auto e = *__begin; // <--- this is QMap::iterator::operator*() fout << e.first << "," << e.second << '\n'; } } 

QMap :: iterator :: iterator *()等同于QMap :: iterator :: value(),并且不给出一对。

写这个最好的方法是没有基于范围的循环:

 auto end = extensions.cend(); for (auto it = extensions.cbegin(); it != end; ++it) { std::cout << qPrintable(it.key()) << "," << qPrintable(it.value()); } 

我用这样的东西来实现我自己的结果。 以防万一别人需要密钥和值。

 { QMap<int,string> map; map.insert(1,"One"); map.insert(2,"Two"); map.insert(3,"Three"); map.insert(4,"Four"); fout<<"Values in QMap 'map' are:"<<endl; foreach(string str,map) { cout<<str<<endl; }; fout<<"Keys in QMap 'map' are:"<<endl; foreach(int key,map.keys()) { cout<<key<<endl; }; } 

另一个方便的方法,从QMap Docs 。 它允许显式访问键和值(Java-Style迭代器):

 QMap<QString, QString> extensions; // ... fill extensions QMapIterator<QString, QString> i(extensions); while (i.hasNext()) { i.next(); qDebug() << i.key() << ": " << i.value(); } 

如果您想要覆盖,请改用QMutableMapIterator

还有另外一个方便的Qt方法,如果你只想读取值而不用键(使用Qtforeach和c ++ 11):

 QMap<QString, QString> extensions; // ... fill extensions foreach (const auto& value, extensions) { // to stuff with value }