Sort Filenames Naturally with Qt

Sort filenames naturally with Qt

If you want to use QCollator to sort entries from the list of entries returned by QDir::entryList, you can sort the result with std::sort():

dir.setFilter(QDir::Files | QDir::NoSymLinks);
dir.setSorting(QDir::NoSort); // will sort manually with std::sort

auto entryList = dir.entryList();

QCollator collator;
collator.setNumericMode(true);

std::sort(
entryList.begin(),
entryList.end(),
[&](const QString &file1, const QString &file2)
{
return collator.compare(file1, file2) < 0;
});

According to The Badger's comment, QCollator can also be used directly as an argument to std::sort, replacing the lambda, so the call to std::sort becomes:

std::sort(entryList.begin(), entryList.end(), collator);

Natural sort of filenames with numbers issue c++

You should compare number part and then string part on equal number part.

inline int findStringPart(const QString &s)
{
...
return stringPart; //Left or Right
}
static bool naturalSortCallback(const QString &s1, const QString &s2)
{
int numberPart1 = findNumberPart(s1);
int numberPart2 = findNumberPart(s2);
QString stringPart1 = findStringPart(s1);
QString stringPart2 = findStringPart(s2);

if(numberPart1 == numberPart2)
return stringPart1 < stringPart2; //"Left" < "Right"
return numberPart1 < numberPart2;
}

How to implement a natural sort algorithm in c++?

I asked this exact question (although in Java) and got pointed to http://www.davekoelle.com/alphanum.html which has an algorithm and implementations of it in many languages.

Update 14 years later: Dave Koelle’s blog has gone off line and I can’t find his actual algorithm, but here’s an implementation.
https://github.com/cblanc/koelle-sort

(valid) QFileInfo causes segv when calling QFileInfo::filename() in std::sort

QCollater::compare(s1, s2) returns "an integer less than, equal to, or greater than zero depending on whether s1 sorts before, with or after s2", hence your comparator doesn't obey strict weak ordering -- it's effectively checking the relationship 's1 != s2' rather than 's1 < s2'. That's undefined behaviour.

Try changing the sort comparator to...

std::sort(fileInfoImageList.begin(), fileInfoImageList.end(),
[&collator](const QFileInfo &a, const QFileInfo &b)
{
QString nameA = a.fileName();
QString nameB = b.fileName();
return collator.compare(nameA, nameB) < 0;
});

Is there a Qt Dialog or Widget to interactively sort a string list?

Qt already supports it, there's nothing for you to do: The standard views automatically support internal drag and drop, where items are moved around to change the order in which they are displayed.

Further quoting the documentation:

  • To enable item dragging, set the view's dragEnabled property to true.
  • To allow the user to drop both internal or external items within the view, set the view's viewport()'s acceptDrops property to true.
  • To show the user where the item currently being dragged will be placed if dropped, set the view's showDropIndicator property. This provides the user with continuously updating information about item placement within the view.
  • To enable the user to move the items around within the view, we must set the list widget's dragDropMode to QAbstractItemView::InternalMove.

Below is a sscce that you can run to see it in action.

#include <QApplication>
#include <QListWidget>
#include <QListWidgetItem>

int main(int argc, char ** argv)
{
QApplication a(argc, argv);
QListWidget w;
w.addItem("Rosalind");
w.addItem("Celia");
w.addItem("Adam");
w.addItem("Jaques");
w.setDragEnabled(true);
w.setDropIndicatorShown(true);
w.setDragDropMode(QAbstractItemView::InternalMove);
w.show();
return a.exec();
}

Natural Sort of Directory Filenames in C++

There is a function that does exactly what you want in glibc. Unfortunately it is C, not C++, so if you can live with that here is the simplest possible solution "out of the box", without reimplementing anything and reinventing the wheel. BTW: this is exactly as ls -lv is implemented. The most important part of it is the versionsort function which does the natural sort for you. It is used here as a comparison function for scandir.
The simple example below prints all files/directories in current directory sorted as you wish.

#define _GNU_SOURCE
#include <dirent.h>
#include <stdlib.h>
#include <stdio.h>

int main(void)
{
struct dirent **namelist;
int n,i;

n = scandir(".", &namelist, 0, versionsort);
if (n < 0)
perror("scandir");
else
{
for(i =0 ; i < n; ++i)
{
printf("%s\n", namelist[i]->d_name);
free(namelist[i]);
}
free(namelist);
}
return 0;
}

C++ - Changing the sorting for custom QSortFilterProxyModel

You should call QSortFilterProxyModel::invalidate to indicate that the current sorting is invalidated, i.e. a new sort action should be performed.

Note that calling sort explicitly will also work when dynamicSortFilter is false or you specify another column or order as can be seen in the code:

void QSortFilterProxyModel::sort(int column, Qt::SortOrder order)
{
Q_D(QSortFilterProxyModel);
if (d->dynamic_sortfilter && d->proxy_sort_column == column && d->sort_order == order)
return;
d->sort_order = order;
d->proxy_sort_column = column;
d->update_source_sort_column();
d->sort();
}

Qt4 QMenu items sorting

Once added, I don't think you can reorder. While you are creating though you could use the QWidget::insertAction method to place it exactly where you want it.

void QWidget::insertAction ( QAction * before, QAction * action )

Otherwise you could use QWidget::addActions. Create your list of Actions and sort it before adding to the QMenu.

void QWidget::addActions ( QList<QAction *> actions )

Sort actual QMap by key

You have several appoaches that you could take:

  • Store the keys as integers after converting QString to an integer.

  • You can use the compare class for std::map as per the example:

  • You can try to use specialize this template function that QMap uses for the comparison.

main.cpp

#include <QMap>
#include <QDebug>
#include <map>

struct str_num_compare {
bool operator() (const QString& lhs, const QString& rhs) const
{return lhs.toInt()<rhs.toInt();}
};

int main()
{
QStringList stringList{"1", "10", "11", "2", "3", "4"};

QMap<int, QString> map;
foreach (const QString &string, stringList)
map.insert(string.toInt(), string);
qDebug() << "Integer key approach:" << map;

std::map<QString, QString, str_num_compare> std_map;
foreach (const QString &string, stringList)
std_map[string] = string;
qDebug() << "QString key approach with std::map:";
for (auto item : std_map)
qDebug() << item.first;

return 0;
}

main.pro

TEMPLATE = app
TARGET = main
QT = core
CONFIG += c++11
SOURCES += main.cpp

Build and Run

qmake && make && ./main

Output

Integer key approach: QMap((1, "1")(2, "2")(3, "3")(4, "4")(10, "10")(11, "11"))
QString key approach:
"1"
"2"
"3"
"4"
"10"
"11"


Related Topics



Leave a reply



Submit