2

从 Qt 文档中关于QMap::iterator

与以任意顺序存储项目的 QHash 不同,QMap 存储按 key 排序的项目。共享相同键的项目(因为它们是使用 QMap::insertMulti() 插入的,或者由于 unite() 插入)将连续出现,从最近插入的值到最近最少插入的值。

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

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},

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

例如,首先ID,然后logging_id,然后calibration_id等等。所以我需要选择除QMapand之外的其他内容QHash

问题:

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

4

3 回答 3

3

您可以使用两个 QVector,或者使用 QVector<QPair<QString, int>> 代替。

于 2021-09-29T09:41:04.987 回答
1

这是提供此功能的 QHash 衍生产品的开始。免责声明:这并不完全完美!并非 QHash 的每个功能/特性都已被考虑在内。只要你只使用这里提供的函数/操作符重载,你肯定没问题。如果有人想继续开发这个并重新发布一个真正“完成”的课程,那就太好了!

请注意,使用 this 与自然 QHash 相比,性能当然会有所下降,并且内存消耗会增加,但对于应该可以忽略不计的小型数据集。

有序哈希

#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
于 2021-12-21T13:43:37.663 回答
0

不在 QT 中(至少据我所知)。你可以使用 Boost,例如 boost::multiindex 吗?另一种选择是在一个类中将 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));}
};

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

于 2021-09-28T22:45:56.260 回答