Как отсортировать QList по определенному порядку (не по алфавиту)?

У меня есть QList<m_User> с

m_User {
    QString status;
    QString firstName;
    QString lastName;
    QDate joinDate;
    QDate leaveDate;
}

status здесь может быть: terminated, in test, requested, activated.

Порядок сортировки для status должен быть следующим: activated -> terminated -> requested -> in test

Этот QList должен быть отсортирован в следующем порядке:

  1. статус (с порядком, как указано выше)
  2. если статус тот же, мы сортируем firstName, на этот раз по алфавиту
  3. если имя совпадает, мы сортируем фамилию, также по алфавиту

Таким образом, результат должен выглядеть

----------------------------------------------------------
| firstName | lastName |  status  | joinDate | leaveDate |
----------------------------------------------------------
|     A     |    C     |activated |   bla    |    bla    |
|     A     |    D     |activated |   bla    |    bla    | 
|     B     |    E     |activated |   bla    |    bla    |

|     A     |    F     |terminated|   bla    |    bla    | 
|     A     |    G     |terminated|   bla    |    bla    | 
|     B     |    H     |terminated|   bla    |    bla    |

|     A     |    I     |requested |   bla    |    bla    | 
|     B     |    I     |requested |   bla    |    bla    | 
|     B     |    K     |requested |   bla    |    bla    |

|     A     |    L     | in test  |   bla    |    bla    |  
|     B     |    L     | in test  |   bla    |    bla    |
|     B     |    M     | in test  |   bla    |    bla    |

person trangan    schedule 18.10.2017    source источник


Ответы (2)


    bool compareUsers(const m_User &u1, const m_User &u2)
    {
        if(u1.status != u2.status)
        {
            //compare all possible combination if statuses of the
            //u1 user and u2 user and return which has priority

            //example activated has priorty over terminated
            if(u1.status == "activated" && u2.status =="terminated")
            {
                return true;
            }
            else if(u1.status == "terminated" && u2.status =="activated")
            {
                return false;
            }
            ...
            ..
            .
        }
        else if(u1.firstName != u2.firstName)
        {
            return u1.firstName > u2.firstName;
        }
        else
        {
           return u1.lastName > u2.lastName; 
        }
    }

а затем просто вызовите предикат в функции сортировки

QList<m_User> list;
qSort(list.begin(), list.end(), compareUsers);
person Angel.Risteski    schedule 18.10.2017
comment
вау, ваше решение легко понять :). Вот у меня 4 статуса, значит должно быть 6 пар статуй для сравнения, не так ли? - person trangan; 18.10.2017
comment
Вы можете хранить все доступные статусы в QStringList и использовать QStringList::indexOf. метод получения индекса. Тогда вы можете просто сравнить индексы. Это избавит вас от необходимости иметь кучу if else if операторов. - person thuga; 18.10.2017
comment
Да, @thuga дает вам отличную идею, у вас есть мое решение, которое вам просто нужно реализовать. Это просто и легко :) - person Angel.Risteski; 18.10.2017
comment
спасибо вам, ребята. Я принял это решение. Хорошего дня! :) - person trangan; 18.10.2017
comment
@thuga Для этой строки qSort(list.begin(), list.end(), compareUsers); я получил это сообщение об ошибке Error 25 error C3867: 'QcgMainLogic::compareUsers': function call missing argument list; use '&QcgMainLogic::compareUsers' to create a pointer to member. Вы знаете, ребята, что это значит? ` - person trangan; 18.10.2017
comment
@Angel.Risteski Должен ли я определить в заголовке compareUsers как static, а затем qSort(list.begin(), list.end(), &compareUsers);? - person trangan; 18.10.2017
comment
Вы должны использовать std::sort вместо qsort (как уже было указано в другом ответе). Либо сделайте свою функцию-член статическим членом, либо просто сделайте ее функцией, не являющейся членом. - person thuga; 18.10.2017
comment
спасибо @thuga. Я думаю, что проблема здесь должна быть о static. потому что я тоже использовал std::sort уже, просто забыл написать. :) - person trangan; 18.10.2017

Вы можете добавить функцию lessThen в свой класс/структуру, а затем при необходимости создать пересылку для qSort. Пример:

class m_User {
public:
bool operator<(const m_User other) const {
        return a<other.a;
    }
};

template <typename T>
struct ForwardLessThen
{     
  bool operator()(const T* a, const T* b) const     
  {
    return *a < *b;
  } 
}; 

qSort(list.begin(), list.end(), ForwardLessThen<m_User>());

если вы используете С++ 11/14, вы можете использовать лямбды

QList<const m_User*> l;
qSort(l.begin(), l.end(), 
      [](const m_User* a, const m_User* b) -> bool { return a->firstName() < b->firstName(); //implement your logic here
}); 

В Qt5 qSort фактически устарел, и вы должны использовать функцию std::sort.

std::sort(container.begin(), container.end(), qLess<T>());

Взгляните на алгоритмы на основе шаблонов в QtAlgorithms.

EDIT: Или, если вы планируете использовать какие-либо модели представления (например, ListView), вы даже можете реализовать собственную QSortFilterProxyModel

person Xplatforms    schedule 18.10.2017
comment
благодарю вас. Нет, вам, ребята, проще представить этот вид. Я до сих пор не могу представить, какой должна быть моя логика для сортировки status с лямбда-выражениями :( - person trangan; 18.10.2017
comment
почему бы вам просто не сравнить строки? И после этого используйте некоторые состояния if-else... doc.qt.io/ qt-5/qstring.html#сравнить - person Xplatforms; 18.10.2017
comment
Спасибо за вашу поддержку. Я новичок в этой области, поэтому мне легче выполнить ответ Ангела, поэтому я его принял. Я также проголосовал за ваш ответ. Хорошего дня! :) - person trangan; 18.10.2017
comment
Похоже, что qLess() также устарел - person Mohammad Kanan; 20.02.2021