QT中是否有类似地图的工具可以迭代插入的索引?

Is there a map-like tool in QT that can be iterated over inserted index?

来自关于 QMap::iterator 的 Qt 文档:

Unlike QHash, which stores its items in an arbitrary order, QMap stores its items ordered by key. Items that share the same key (because they were inserted using QMap::insertMulti(), or due to a unite()) will appear consecutively, from the most recently to the least recently inserted value.

我想要的是通过插入的索引来插入一个map。例如这张地图。

const static QMap<QString, int> MEASUREMENT_COLUMNS{{"ID", MY_SQL_BIGINT}, {"logging_id", MY_SQL_INT}, {"calibration_id", MY_SQL_INT}, {"logging_comment", MY_SQL_VARCHAR255}, {"measurement_date_time", MY_SQL_DATETIME}, {"ADC0", MY_SQL_FLOAT},
                                                    {"ADC0", MY_SQL_FLOAT},
                                                    {"ADC1", MY_SQL_FLOAT},
                                                    {"ADC2", MY_SQL_FLOAT},

但问题正如上面关于 QMapQHashmap 的文档所述。如果我想通过插入的索引迭代地图,它们将不起作用。

比如先ID,然后logging_id,然后calibration_id等等。 所以我需要 select 除了 QMapQHash.

问题:

QT中有没有类似地图的工具可以迭代插入的索引?

QT 中没有(至少据我所知)。 你能使用 Boost 吗? boost::multiindex?另一种选择是在 class +- 中将 map 与 vector 结合起来,就像这样(这可能包含错误;它应该说明总体思路,而不是一段完整的代码):

template<typename K, typename V>
class indexed_map
{
  map<K, V> m_map;
  vector<K> m_insertionOrder;
public:
  void insert(const K& k, const V& v)
  {
    m_map.insert(k,v);
    m_insertionOrder.push_back(k);
  }

  V byKey(const K& k) const {return m_map.at(k)};
  V byOrder(size_t n) const {return m_map.at(m_insertionOrder.at(n));}
};

当然,您必须编写一些样板文件(好吧,实际上很多样板文件),迭代器可能也很棘手。

您可以使用两个 QVector,或者使用 QVector > 代替。

这是提供此功能的 QHash 派生的开始。免责声明:这并不完全完美!并非 QHash 的每个功能/特性都已被考虑在内。只要您只使用此处提供的函数/运算符重载,您肯定会没事的。如果有人想继续开发这个并重新发布一个真正“完成”的 class,那就太好了!

注意性能当然会下降一点,内存消耗会增加,使用这个与自然的QHash相比,但是对于小数据集应该可以忽略不计。

OrderedHash.h

#ifndef ORDEREDHASH_H
#define ORDEREDHASH_H

#include <QHash>
#include <QVector>
#include <QDataStream>
#include <QDebug>

template<class K, class V>
class OrderedHash : public QHash<K,V>
{
public:
    using QHash<K,V>::QHash;

#ifdef Q_COMPILER_INITIALIZER_LISTS
    OrderedHash( std::initializer_list<std::pair<K, V>> list )
        : QHash<K,V>::QHash()
    { foreach( auto p, list ) insert( std::get<0>(p), std::get<1>(p) ); }
#endif

    // Returns the keys in the order they were inserted.
    // If the ordered keys vector is blatantly out of sync with the hash 
    // (as may occur via the use of QHash functions not accounted for
    // by this override!), this returns UNordered keys, since those are at
    // least accurate.
    QList<K> orderedKeys() const {
        if( QHash<K,V>::size() != orderedKeys_.size() )
        {
            qWarning() << "OrderedHash keys are out of sync!";
            return QHash<K,V>::keys();
        }
        return orderedKeys_.toList();
    }

    // This insert override "appends" to the "end" of the hash. If the key is
    // already present, the entry is "moved" to the new end.
    typename QHash<K,V>::iterator insert( const K &key, const V &value )
    {
        //qDebug() << "OrderedHash insert: " << key << ":" << value;
        orderedKeys_.removeAll( key );
        orderedKeys_.push_back( key );
        return QHash<K,V>::insert( key, value );
    }

    // This additional update function perseveres the "key order" while
    // modifying the value. If the key is not yet present, the entry is
    // appended to the "end" of the hash.
    typename QHash<K,V>::iterator update( const K &key, const V &value )
    {
        if( !QHash<K,V>::contains( key ) ) return insert( key, value );
        return QHash<K,V>::insert( key, value );
    }

    int remove( const K &key )
    {
        orderedKeys_.removeAll( key );
        return QHash<K,V>::remove( key );
    }

    void clear()
    {
        orderedKeys_.clear();
        QHash<K,V>::clear();
    }

private:
    QVector<K> orderedKeys_;
};

// COPIED AND TWEAKED QT SOURCE FOR THESE STREAM OPERATOR OVERLOADS
template <class Key, class T>
Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, OrderedHash<Key, T> &hash)
{
    QDataStream::Status oldStatus = in.status();
    in.resetStatus();
    hash.clear();

    quint32 n;
    in >> n;

    for (quint32 i = 0; i < n; ++i) {
        if (in.status() != QDataStream::Ok)
            break;

        Key k;
        T t;
        in >> k >> t;
        /* ORGINAL QT SOURCE
        hash.insertMulti(k, t);
        */
        //---------------------------------
        hash.insert(k, t);
        //---------------------------------
    }

    if (in.status() != QDataStream::Ok)
        hash.clear();
    if (oldStatus != QDataStream::Ok)
        in.setStatus(oldStatus);
    return in;
}

template <class Key, class T>
Q_OUTOFLINE_TEMPLATE QDataStream &operator<<(QDataStream &out, const OrderedHash<Key, T>& hash)
{
    out << quint32(hash.size());
    /* ORGINAL QT SOURCE
    typename QHash<Key, T>::ConstIterator it = hash.end();
    typename QHash<Key, T>::ConstIterator begin = hash.begin();
    while (it != begin) {
        --it;
        out << it.key() << it.value();
    }
    */
    //---------------------------------
    const QList<Key> keys( hash.orderedKeys() );
    foreach( auto key, keys ) out << key << hash.value(key);
    //---------------------------------
    return out;
}

#endif // ORDEREDHASH_H