I have the following datastructure.
QList<QVariant> fieldsList
How can I sort this list? This list contains strings. I want to sort the fieldList alphabetically?
In Qt5, it seems qSort is deprecated. It's recommended to use:
#include <algorithm>
QList<QVariant> fieldsList;
std::sort(fieldsList.begin(), fieldsList.end());
Reference: site
I would do sorting in the following way:
// Compare two variants.
bool variantLessThan(const QVariant &v1, const QVariant &v2)
{
return v1.toString() < v2.toString();
}
int doComparison()
{
[..]
QList<QVariant> fieldsList;
// Add items to fieldsList.
qSort(fieldsList.begin(), fieldsList.end(), variantLessThan);
}
Update:
in QT5 the qSort obsoleted. But it is still available to support old source codes. It is highly recommended to use std::sort instead of that in new codes.
int n;
int i;
for (n=0; n < fieldsList.count(); n++)
{
for (i=n+1; i < fieldsList.count(); i++)
{
QString valorN=fieldsList.at(n).field();
QString valorI=fieldsList.at(i).field();
if (valorN.toUpper() > valorI.toUpper())
{
fieldsList.move(i, n);
n=0;
}
}
}
Related
I am using qtxml to write a xml file, I found that the output xml file's element attributes has different order each time I run my program.
I read the source code and found that qtxml use QHash to store element attributes, which will lead to output XML file's element attributes has different order each time I run my program.
Why not use QMap to store elements' attributes? which will produce an ordered attribute.
What's the difference between QHash and QMap in this scenario?
QMap is a Red-black tree.
QHash is implemented using a hash table
QMap is slower than QHash. QMap searches are faster than QHash with fewer than 10 items.
#include <QtCore/QtCore>
#include <unordered_map>
#ifndef CONTAINER
#error CONTAINER must be defined to QMap, QHash, std::map or std::unordered_map
#endif
namespace std {
/* std::hash specialization for QString so it can be used
* as a key in std::unordered_map */
template <class Key>
struct hash;
template <>
struct hash<QString> {
typedef QString Key;
typedef uint result_type;
inline uint operator()(const QString& s) const { return qHash(s); }
};
}
int main(int argc, char** argv)
{
if (argc < 2)
qFatal("" Missing number of element to add "");
QByteArray a = argv[1];
uint num = a.toUInt();
// creates an array of random keys
QVector<QString> strs(num);
for (int i = 0; i < num; ++i)
strs[i] = qvariant_cast<QString>(qrand());
CONTAINER<QString, QString> c;
for (uint i = 0; i < num; ++i) {
QString& k = strs[i];
c[k] = QString::number(i);
}
quint64 it = 0;
const QString* arr = strs.constData();
QElapsedTimer t;
t.start();
while (t.elapsed() < 1000) {
const QString& k = arr[(++it) * 797 % num];
c[k]; // perform a lookup
}
qDebug() << it / 1000;
}
The higher the iteration value, the best. The scale of the number of elements is logarithmic. It should be expected that for QHash the value will not change with increasing number of elements, and for QMap it should be equal to log N, which corresponds to a straight line on a logarithmic scale.
However, with a large number of elements, the results are not in favor of QMap.
This is most likely the reason why QHash is used.
I'm trying to combine all the elements inside a vector as a new string but I can't get the example how to do this. Most of the examples are concatenating between vectors and also in C++ std::cout. I'm not sure how to do it in MFC VC++.
Let's say I have a vector (in CString) with the elements I am a naughty boy. How can I combine them and saved them as a
CString str;
str = "I am a naughty boy"
Edited:
struct REVLISTDATA {
CString str_;
REVLISTDATA(CString str_element) : str_(str_element) {}
};
std::vector<REVLISTDATA> vec;
If I am well understood your request, here is an approach:
for (size_t i = 0; i < vec.size(); ++i)
{
str.AppendFormat(vec.at(i));
if (i < vec.size() - 1)
str.AppendFormat(_T(" ")); // spaces between words
}
presuming that your vec is std::vector<CString>
Edit: So, instead of str.AppendFormat(vec.at(i)); you should use str.AppendFormat(vec.at(i).str_);
Later edit: I have tried the following code and work ok:
struct REVLISTDATA
{
CString str_;
REVLISTDATA(CString str_element) : str_(str_element) {}
};
std::vector<REVLISTDATA> vec;
vec.push_back(REVLISTDATA("I"));
vec.push_back(REVLISTDATA("am"));
vec.push_back(REVLISTDATA("a"));
vec.push_back(REVLISTDATA("naughty"));
vec.push_back(REVLISTDATA("boy"));
CString str;
for (size_t i = 0; i < vec.size(); ++i)
{
str.AppendFormat(vec.at(i).str_);
if (i < vec.size() - 1)
str.AppendFormat(_T(" ")); // spaces between words
}
So, I guess you exception is coming from other way.
I have the following datastructure.
QList<QVariant> fieldsList
How can I sort this list? This list contains strings. I want to sort the fieldList alphabetically?
In Qt5, it seems qSort is deprecated. It's recommended to use:
#include <algorithm>
QList<QVariant> fieldsList;
std::sort(fieldsList.begin(), fieldsList.end());
Reference: site
I would do sorting in the following way:
// Compare two variants.
bool variantLessThan(const QVariant &v1, const QVariant &v2)
{
return v1.toString() < v2.toString();
}
int doComparison()
{
[..]
QList<QVariant> fieldsList;
// Add items to fieldsList.
qSort(fieldsList.begin(), fieldsList.end(), variantLessThan);
}
Update:
in QT5 the qSort obsoleted. But it is still available to support old source codes. It is highly recommended to use std::sort instead of that in new codes.
int n;
int i;
for (n=0; n < fieldsList.count(); n++)
{
for (i=n+1; i < fieldsList.count(); i++)
{
QString valorN=fieldsList.at(n).field();
QString valorI=fieldsList.at(i).field();
if (valorN.toUpper() > valorI.toUpper())
{
fieldsList.move(i, n);
n=0;
}
}
}
I need somthing similar to QSet, but I need the items to be saved on the order I inserted them
is there such thing?
I am not aware of anything like that out of the box in neither Qt nor STL. Boost has something like that I think but it is not that hard to do this yourself.
You could do a wrapper around QHash like this:
template<typename T>
class MySet : QHash<T, int>
{
public:
using QHash<T, int>::QHash;
QVector<T> values() //this 'hides' the base QHash::values() of QHash
{
QVector<T> vec(count());
for(auto it = cbegin(); it != end(); ++it)
{
vec[it.value()] = it.key();
}
return vec;
}
void insert(const T &value)
{
if(!contains(value))
{
insert(value, m_Data.count());
}
}
};
The usage is quite similar to QSet:
MySet<QString> set;
set.insert("1");
set.insert("2");
set.insert("3");
qDebug() << set.values();
And that prints the values in order. If you need more complete support like iterators also iterating in your desired order you would have to reimplement more functionality but the gist of it would be the same. After all QSet is internally QHash as well. Note that the above does not support removal without modification.
Maybe a QList or a QVector could help.
QList<QString> stringList;
//By the way, Qt provides QStringList as a typedef for QList<QString>
stringList.append("A");
stringList.append("B");
qDebug() << stringList.at(0); //A
qDebug() << stringList.at(1); //B
I have a QList consist of QVector3D. A QVector3D represents a vertex or a point. This List holds also all vertices of a STL-File. The problem is that a vertex exist multiple times in the list. In need a list of the unique vertices of a STL-File. How can i implement it with Qt 5.0.2?
QSet uses a hash-function for ensuring the uniqueness of the value (QMap uses operator <)
There is no qHash implementation for QVector3D in Qt.
You could implement your own one e.g. as in example:
//place anywhere in Qt-code
#include <QSet>
#include <QVector3D>
#include <QList>
uint qHash(const QVector3D &v)
{
return qHash( QString( "%1x%2x%3" ).arg(v.x()).arg(v.y()).arg(v.z()) ) ;
}
int foo()
{
QList<QVector3D> uvector3D_1;
QSet<QVector3D> uvector3D_2;
uvector3D_2 = QSet<QVector3D>::fromList(uvector3D_1);
return 0;
}
static int testFoo = foo();
Of cause it is not the fastest one, it relies on Qt's function qHash for QString. But I think it's good for demonstration.
QList<QVector3D> originalVector = ...;
then either:
QSet<QVector3D> noDublicatesSet = QSet<QVector3D>::fromList(originalVector);
or
QSet<QVector3D> noDublicatesSet = originalVector.toSet();
also you can add something like if you need QList back..
QList<QVector3D> destinationVector = QList<QVector3D>::fromSet(noDublicatesSet);
you also will need those things (sorry has them in my code for ages.. forgot that they are external).. you might want to change hash function:
#define ROTL10(x) (((x) << 10) | (((x) >> 22) & 0x000000ff))
#define ROTL20(x) (((x) << 20) | (((x) >> 12) & 0x0000ffff))
uint qHash(double data)
{
union U {
quint64 n;
double f;
};
U u;
u.f = data;
return u.f;
}
inline uint qHash(const QVector3D &v, uint seed)
{
return qHash(v.x()) ^ ROTL10(qHash(v.y())) ^ ROTL20(qHash(v.z()));
}
P.S. that's a code for Qt 5.0, actually to add missing qHash() for vectors, that's why they dont fit in QSet/QHash by default
Starting from Qt 5.14, you can use the new constructor:
template <typename InputIterator> QSet::QSet(InputIterator first, InputIterator last
Here is an example taken from the docs:
// For example, if you have code like
QStringList list;
QSet<QString> set = QSet<QString>::fromList(list);
// you can rewrite it as
QStringList list;
QSet<QString> set(list.begin(), list.end());