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'
e
はQPair
型ではありませんか?
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';
}
最適化に興味のある人のために、いくつかのアプローチを試し、いくつかのマイクロベンチマークを行い、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スタイルは、このベンチマークで非常によく似たパフォーマンスを持っています
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());
}
「古い」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<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スタイルのイテレータ):
QMap<QString, QString> extensions;
// ... fill extensions
QMapIterator<QString, QString> i(extensions);
while (i.hasNext()) {
i.next();
qDebug() << i.key() << ": " << i.value();
}
上書きできるようにするには、代わりにQMutableMapIterator
を使用します。
キーを使用せずに値を読み取ることにのみ関心がある場合は、別の便利なQt
メソッドがあります(Qt
s foreach
およびc ++ 11を使用)。
QMap<QString, QString> extensions;
// ... fill extensions
foreach (const auto& value, extensions)
{
// to stuff with value
}