web-dev-qa-db-ja.com

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'

eQPair型ではありませんか?

49
user336635

firstおよびsecondを使用したSTLスタイルが必要な場合は、次のようにします。

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

Qtが提供するものを使用したい場合、これを行います:

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

最適化に興味のある人のために、いくつかのアプローチを試し、いくつかのマイクロベンチマークを行い、STLスタイルのアプローチは非常に高速であると結論付けることができます

私はこれらのメソッドで整数を追加しようとしました:

  • QMap :: values()
  • Javaスタイルのイテレータ(ドキュメントで推奨)
  • STLスタイルのイテレータ(ドキュメントでも推奨)

そして、私はそれを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年7月編集:新しいラップトップ(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

STLスタイルとJavaスタイルは、このベンチマークで非常によく似たパフォーマンスを持っています

22
Fezvez

QMap :: iteratorはkey()とvalue()を使用します。これらは Qt 4.8のドキュメント または Qt-5のドキュメント で簡単に見つけることができます。

編集:

範囲ベースの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()と同等であり、ペアを与えません。

これを記述する最良の方法は、範囲ベースのforループを使用しないことです。

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

「古い」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リンクを確認してください

13
Tim Meyer

私は自分の結果を達成するために、このようなものを使用しました。誰かがキーと値を別々に必要とした場合に備えて。

{
   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;
   }; 
}  
1
Thierry Joel

QMap Docs からの別の便利な方法。キーと値への明示的なアクセスを許可します(Javaスタイルのイテレータ):

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

上書きできるようにするには、代わりにQMutableMapIteratorを使用します。

キーを使用せずに値を読み取ることにのみ関心がある場合は、別の便利なQtメソッドがあります(Qts foreachおよびc ++ 11を使用)。

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