简体   繁体   中英

How to sort QMap<QString, myStruct>?

I have a QMap<QString, myStruct> with

myStruct {
    QString firstname;
    QString lastname;
    QString status;
}

How can I sort this QMap according to priority order: status then firstname then lastname ?

As far as I understand, you'd like to retrieve the values of the map sorted in the mentioned way, but still have access to the key. Right?

Quickly speaking, a map is a collection of <key, value> pairs automatically sorted by key , then you may try a list of <value, key> pairs manually sorted by value instead. Something like QList<QPair<myStruct, QString>> , while overriding the operator< for myStruct .

struct myStruct {
    QString firstname;
    QString lastname;
    QString status;

    bool operator<(const myStruct& o) const {
      return std::tie(status, firstname, lastname) <
             std::tie(o.status, o.firstname, o.lastname);
    }
};

QMap<QString, myStatus> map; // your original map
QList<QPair<myStatus, QString>> inv;

// Populate the inverted list
for (auto k : map.keys()) {
  inv.append(QPair<myStatus, QString>(map[k], k));
}

std::sort(std::begin(inv), std::end(inv));

for (auto p : inv) {
  qDebug() << p.first.status << p.first.firstname << p.first.lastname << p.second;
}

Of course, it is a one-time use structure that doesn't keep updated with your original map, but you mentioned that the map is fixed (constant?) so it may not be a problem then.

BTW, a QMap can be used for the inverse look-up but only in the case the values of the myStruct part are also unique (so they can be used also as a key), otherwise you may overwrite values when constructing the inverse map.

Note: The std::tie is used just to simplify the sorting condition for tuples (so you'd need to include <tuple> ).

UPDATE

Answering one of your comments: Yes, you can also specify your own comparison predicate and then avoid overriding the operator< , but I think it is harder to read and less re-usable:

std::sort(std::begin(inv), std::end(inv),
  [](const QPair<myStatus, QString>& lhs, const QPair<myStatus, QString>& rhs) {
    return std::tie(lhs.first.status, lhs.first.firstname, lhs.first.lastname) <
           std::tie(rhs.first.status, rhs.first.firstname, rhs.first.lastname);
});

Of course, you can implement that comparison lambda as you want, I've used the std::tie again to simplify the logic in the post. The downside is that if you need to generate the inverse map in several places you'd have to repeat the lambda expression everywhere (or create a function to create the inverse map of course).

As a side note and in case you are curious, lhs and rhs refers to left-hand side and right-hand side respectively, in this case they are used as lhs < rhs by the sorting algorithm for comparing the elements.

Finally, if you'd want to avoid the std::tie you'd have to make the comparisons manually (code below modifies the operator< of the first version):

bool operator<(const myStruct& o) const {
  if (status < o.status) return true;
  if (status > o.status) return false;
  // status == o.status, move to next attribute

  if (firstname < o.firstname) return true;
  if (firstname > o.firstname) return false;
  // firstname== o.firstname, move to next attribute

  if (lastname < o.lastname) return true;
  if (lastname > o.lastname) return false;

  return false; // are equal
}

You can't sort a QMap manually, you'll have to use a QList (or QVector ) for that and use std::sort on it. Use QMap::values() to extract the values (structs) from the map into a list, then implement a compare function/method and call it with std::sort . See cbuchart s answer for some hints how to do this.

Keeping map and list in sync when the values change is a different issue, if this is a requirement you should create a separate question, adding a MCVE and more details on what you tried.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM