用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
?
如果您想要first
和second
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
作为auto
types:
template<class Map> struct RangeWrapper { typedef typename Map::iterator MapIterator; 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
方法,如果你只想读取值而不用键(使用Qt
的foreach
和c ++ 11):
QMap<QString, QString> extensions; // ... fill extensions foreach (const auto& value, extensions) { // to stuff with value }