PDA

View Full Version : QMap sorting according to QLocale



sedi
30th January 2013, 20:54
Is it possible to convince a QMap<QString, QString> to sort its items according to my program's locale?
(The program's locale is not necessarily the same as the system's locale.)

My keys are a bunch of Names of which some start with/contain german umlauts.
They appear in wrong order:
E.g., iterating through, an "Ömer" should appear after "Othello", not after "Zinn" as it does right now.

maximebd
30th January 2013, 21:27
I believe that for performance reason, QMap probably doesn't use locales to sort and only relies on the numerical value of UTF-16 characters. What you could do is to sort the list of keys using a combination of qsort and QString::localeAwareCompare like so:



QList<QString> keyList = myMap.keys();
qSort(keyList.begin(), keyList.end(), QString::localeAwareCompare);
foreach(QString key, keyList)
{
const auto& data = myMap[key];
// do something...
}

ChrisW67
30th January 2013, 23:19
Or perhaps something like this is acceptable in your application:


class LocaleString: public QString {
public:
LocaleString(const char *s): QString(s) { }
LocaleString(const QString &s): QString(s) { }
};

inline bool operator<(const LocaleString &lhs, const LocaleString &rhs)
{
return (QString::localeAwareCompare(lhs, rhs) < 0);
}


// then
QMap<LocaleString,int> map;
map.insert(QString::fromUtf8("Ömer"), 1);
map.insert("Othello", 2);
map.insert("Zinn", 3);
foreach(const LocaleString &s, map.keys())
qDebug() << s;

sedi
31st January 2013, 20:12
Thank you both very much for your help!

You've helped me getting it solved indeed!

My method shall return a QStringList with names. Those names should be put together from first and family name in a user definable order
(either "Gates, Bill" or rather "Steve Jobs") and a sorting depending on first or family name.

I simply canNOT use a QMap for such a sorting job, which I did (not knowing alternatives at that time).
I'd actually constructed a really messy and overly complicated thing in the first place.

Being fairly new to OOP I'd missed the obvious thing to do: create a "Name" class with some getter and setter methods and an overloaded operator< and then do a simple sort on a QList<Name>.
According to your ideas and the QMap docs I've implemented it like this way:

const inline bool operator<(const Name &n1, const Name &n2)
{
int comp;
if (n1.sortingOrder()==Name::familyFirst)
{
comp=QString::localeAwareCompare(n1.family(),n2.fa mily());
if (comp!=0)
return comp < 0;
comp=QString::localeAwareCompare(n1.first(),n2.fir st());
if (comp!=0)
return comp < 0;
comp=QString::localeAwareCompare(n1.id(),n2.id());
return comp<0;
} else {
comp=QString::localeAwareCompare(n1.first(),n2.fir st());
if (comp!=0)
return comp < 0;
comp=QString::localeAwareCompare(n1.family(),n2.fa mily());
if (comp!=0)
return comp < 0;
comp=QString::localeAwareCompare(n1.id(),n2.id());
return comp<0;
}
}


I now build a list of this class and just sort it:

QList<Name> nameList;
//fill the list, e.g. like this, but in a loop:
//nameList.append(Name(first, family, id);
//nameList.last().setSortingOrder(Name::familyFirst) ;
qSort(nameList);


This has *so* many advantages over my old approach...

Thank you!