Unsorted QVector
-
Hi,
I have a QVector<QString>, which should store filepaths, like
./abc/1.jpg
./abc/2.jpg
./abc/3.jpg
.
.
.
./abc/1209.jpgBut instead of storing it in the above order, it's storing like
./abc/1.jpg
./abc/10.jpg
./abc/100.jpg
./abc/1000.jpg
./abc/1001.jpg
.
.How can I store the image filepath in numeric sequence?
-
Hi @sayan275
Unfortunately because of the standard string compare functions you get the behavior you are seeing. The easiest way to solve this in an ideal sense is to prepend '0' to all the numbers. This is not practical or desirable. Instead, what you will need to do is write your own smart compare function that has some knowledge of your file names.
Luckily, QVector, QList, and QMap can be used like the C++Library std::vector, std::list, and std::map.
Here is what I am referring to:
int my_comparator (const QString& lhs, const QString& rhs)
{
// Write some smart stuff to compare the files with numeric ordering
if (lhs < rhs) return -1;
else if (lhs > rhs) return 1;
else return 0;
}... more code here ...
std::sort (my_vector.begin (), my_vector.end (), my_comparator);
Unfortunately, there is no easy way to do this except your custom function. Luckily everything you need is available. I would suggest you look online for a good test comparator that does what you want. Here is a decent article you can read about human sorting.
https://blog.codinghorror.com/sorting-for-humans-natural-sort-order/
-
Hello,
This is because you are sorting strings, so 10, 100, etc.. comes before 2 in alphabet order.
You have to convert them to numbers to sort them correctly.You can use std::sort() with custom "Compare" method for that.
using lambda :
std::sort(vector.begin(), vector.end(), [](const QString& a, const QString b) { bool okA, okB; int ia = QFileInfo(a).baseName().toUint(&okA); int ib = QFileInfo(a).baseName().toUint(&okB); if(!okA || !okB) return a < b; return ia < ib; });
without lambda:
bool compareNumberFileName(const QString& a, const QString b) { bool okA, okB; int ia = QFileInfo(a).baseName().toUint(&okA); int ib = QFileInfo(a).baseName().toUint(&okB); if(!okA || !okB) return a < b; return ia < ib; } std::sort(vector.begin(), vector.end(), compareNumberFileName);
In case you are using always the same folder, you can store only numbers corresponding to file names in QVector<uint> and then construct the file name when it's necessary.
-
Hi
I was wondering if QStringList would just work if the goal is to just have them in the same order as inserted ? -
@mrjj It's the same with QStringList. Actually the problem is with the container only which contains the qstring paths as sorted,
"./zThumbnail/1004.jpeg"
"./zThumbnail/1005.jpeg"
"./zThumbnail/1006.jpeg"
"./zThumbnail/1007.jpeg"
"./zThumbnail/1008.jpeg"
"./zThumbnail/1009.jpeg"
"./zThumbnail/101.jpeg"
"./zThumbnail/1010.jpeg"
"./zThumbnail/1011.jpeg"
"./zThumbnail/1012.jpeg"
"./zThumbnail/1013.jpeg"QFileInfoList filelistinfo = dir.entryInfoList();
foreach (const QFileInfo &fileinfo, filelistinfo) {
imagePath.push_back(fileinfo.absoluteFilePath());
qDebug() << fileinfo.absoluteFilePath();
} -
@sayan275 neither QVector nor QStringList are sorted!
they are just containers that can be sorted. but if you append or push_back, than new items appear at the end.
so you will have to sort the list yourself, as already suggested.
-
With QMap, the items are always sorted by key.
You can also use the QMap. like this:
QFileInfoList filelistinfo = dir.entryInfoList(QStringList() << "*.jpeg"); QMap<int, QString> map; for (const QFileInfo &fileinfo : qAsConst(filelistinfo)) map[fileinfo.baseName().toInt()] = fileinfo.absoluteFilePath(); for (QString value : qAsConst(map)) qDebug() << value;
-
To add my 2 cents,
you could sort twice, first along the string length than, in blocks, along the string itself. -
I got it done by the below code
QFileInfoList filelistinfo = dir.entryInfoList(); for(const QFileInfo &fileinfo: filelistinfo) imagePath.push_back(fileinfo.absoluteFilePath()); std::sort(imagePath.begin(), imagePath.end(), [](const QString & a, const QString & b) -> bool { return QFileInfo(a).baseName().toInt() < QFileInfo(b).baseName().toInt(); }); qDebug()<<imagePath;