Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to sort QList<QList<QVariant>>
Forum Updated to NodeBB v4.3 + New Features

How to sort QList<QList<QVariant>>

Scheduled Pinned Locked Moved Solved General and Desktop
16 Posts 4 Posters 6.9k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • VRoninV Offline
    VRoninV Offline
    VRonin
    wrote on last edited by VRonin
    #5

    if the top level Qlist has 100 entries (say 100 rows) and each row has 10 entries each (say 10 columns), I'd like to sort the entire list by the second column

    std::sort(list.begin(),list.end(),[](const QList<QVariant>& a, const QList<QVariant>& b)->bool{return a.at(1)<b.at(1);});

    QAbstractTableModel with a view and when I sort the view using a proxyModel the data source is not in sync with the sort so of course the display is not what I expected

    This is not correct. the QSortFilterProxyModel is the one that takes care of keeping a mapping between the original model and what is displayed. It should work without any problem and show exactly what you expect

    "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
    ~Napoleon Bonaparte

    On a crusade to banish setIndexWidget() from the holy land of Qt

    1 Reply Last reply
    4
    • L Offline
      L Offline
      leinad
      wrote on last edited by
      #6

      I tried using QSortFilterProxyModel but my issue is when I load thousands of rows, over time the load becomes slower and slower which is why I probabaly need to sort externally on my own. If I don't use QSortFilterProxyModel and just assign my QAbstractTableModel to my view, the load is extremely fast. So why when assigning a QSortFilterProxyModel to a view is loading the model so slow? Does the proxymodel index the data somehow?

      Fast load:
      view->setSourceModel(QAbstractTableModel)

      slow load:
      proxyModel->setSourceModel(QAbstractTableModel);
      view->setModel(proxyModel)

      Are there any flags I should set prior to load in the proxy model to speed things up?

      Thanks.

      JonBJ 1 Reply Last reply
      0
      • L leinad

        I tried using QSortFilterProxyModel but my issue is when I load thousands of rows, over time the load becomes slower and slower which is why I probabaly need to sort externally on my own. If I don't use QSortFilterProxyModel and just assign my QAbstractTableModel to my view, the load is extremely fast. So why when assigning a QSortFilterProxyModel to a view is loading the model so slow? Does the proxymodel index the data somehow?

        Fast load:
        view->setSourceModel(QAbstractTableModel)

        slow load:
        proxyModel->setSourceModel(QAbstractTableModel);
        view->setModel(proxyModel)

        Are there any flags I should set prior to load in the proxy model to speed things up?

        Thanks.

        JonBJ Online
        JonBJ Online
        JonB
        wrote on last edited by JonB
        #7

        @leinad said in How to sort QList<QList<QVariant>>:

        So why when assigning a QSortFilterProxyModel to a view is loading the model so slow? Does the proxymodel index the data somehow?

        Yes, and it does sorting/filtering so it's slower. I cannot say whether the slowness you see at 100,000 rows is right or not, I guess sorting that takes a bit of time.

        If you are happy to sort the underlying model explicitly and omit QSortFilterProxyModel you can do that, e.g. via the std::sort() @VRonin has typed in.

        1 Reply Last reply
        1
        • L Offline
          L Offline
          leinad
          wrote on last edited by
          #8

          Thanks. Is there anyway have it sort at the end of the load rather than as it goes? Why is it when I used to use QStandardItemModel and sorted using the treeView it was so much faster? The load was fast too. What happens under the covers using QstandardItemModel that makes such a difference?

          1 Reply Last reply
          0
          • L Offline
            L Offline
            leinad
            wrote on last edited by
            #9

            Well, it looks like Vronin solution worked. I got rid of the proxyModel and attached the view directly to QAbstractTableModel and implemented the sort after the load. It loads and sort very quickly. Now I need to create a signal and slot mechanism to check when a user clicks on a particular column on the view for sorting which I will implement via std::sort.

            Thanks.

            VRoninV 1 Reply Last reply
            2
            • L leinad

              Well, it looks like Vronin solution worked. I got rid of the proxyModel and attached the view directly to QAbstractTableModel and implemented the sort after the load. It loads and sort very quickly. Now I need to create a signal and slot mechanism to check when a user clicks on a particular column on the view for sorting which I will implement via std::sort.

              Thanks.

              VRoninV Offline
              VRoninV Offline
              VRonin
              wrote on last edited by VRonin
              #10

              @leinad said in How to sort QList<QList<QVariant>>:

              Now I need to create a signal and slot mechanism to check when a user clicks on a particular column on the view for sorting which I will implement via std::sort.

              No need to create anything fancy, just reimplement QAbstractItemModel::sort do do the sorting you want and everything else will be handled automatically by Qt

              void MyModel::sort(int column, Qt::SortOrder order = Qt::AscendingOrder){
              emit layoutAboutToBeChanged({QModelIndex()}, QAbstractItemModel::VerticalSortHint);
              std::sort(list.begin(),list.end(),[column,order](const QList<QVariant>& a, const QList<QVariant>& b)->bool{
              if(order == Qt::AscendingOrder)
              return a.at(column)<b.at(column);
              return a.at(column)>b.at(column);
              });
              emit layoutChanged({QModelIndex()}, QAbstractItemModel::VerticalSortHint);
              }
              

              "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
              ~Napoleon Bonaparte

              On a crusade to banish setIndexWidget() from the holy land of Qt

              1 Reply Last reply
              2
              • L Offline
                L Offline
                leinad
                wrote on last edited by
                #11

                That is exactly what I did except for:

                emit layoutAboutToBeChanged({QModelIndex()}, QAbstractItemModel::VerticalSortHint);

                1 Reply Last reply
                0
                • L Offline
                  L Offline
                  leinad
                  wrote on last edited by
                  #12

                  @VRonin said in How to sort QList<QList<QVariant>>:

                  emit layoutChanged({QModelIndex()}, QAbstractItemModel::VerticalSortHint);

                  VRonin,

                  I have another question. Would you know how to handle this case in a sort? It seems to work okay when using QStandardItemModel sorting under Qt but not with the above sorting.

                  So the sorting works fine as is where we sort properly on column 1 which gives us the bottom results. But now within that sort I'd like to sort name1 further using column2 so name1 and name 2 is rearranged in column2 order.
                  If column1 is not a duplicate within the column 0 grouping then no further sort is required. So essentially take the first sort and for duplicate column 0 and column1 values resort using column 2. Is this possible?

                  Example:
                  Think of column 1 as time (consider a string) where we have row data for the same object name with duplicate time, and column 2 is the rowID from a database. So even though technically the sort is correct by time the exact order in the database is governed by the rowID from a database. Essentially sort by time and then by RowID for objects in column0 and 1 that have the same value. For some reason QStandardItemModel handles this all by itself so it would be nice if I can recreate it.

                  column 0 column1 column2
                  name1 123 3
                  name1 123 1
                  name1 123 2
                  name2 345 2
                  name2 345 3
                  name2 345 1

                  result:
                  name1 123 1
                  name1 123 2
                  name1 123 3
                  name2 345 1
                  name2 345 2
                  name2 345 3

                  VRoninV 1 Reply Last reply
                  0
                  • L leinad

                    @VRonin said in How to sort QList<QList<QVariant>>:

                    emit layoutChanged({QModelIndex()}, QAbstractItemModel::VerticalSortHint);

                    VRonin,

                    I have another question. Would you know how to handle this case in a sort? It seems to work okay when using QStandardItemModel sorting under Qt but not with the above sorting.

                    So the sorting works fine as is where we sort properly on column 1 which gives us the bottom results. But now within that sort I'd like to sort name1 further using column2 so name1 and name 2 is rearranged in column2 order.
                    If column1 is not a duplicate within the column 0 grouping then no further sort is required. So essentially take the first sort and for duplicate column 0 and column1 values resort using column 2. Is this possible?

                    Example:
                    Think of column 1 as time (consider a string) where we have row data for the same object name with duplicate time, and column 2 is the rowID from a database. So even though technically the sort is correct by time the exact order in the database is governed by the rowID from a database. Essentially sort by time and then by RowID for objects in column0 and 1 that have the same value. For some reason QStandardItemModel handles this all by itself so it would be nice if I can recreate it.

                    column 0 column1 column2
                    name1 123 3
                    name1 123 1
                    name1 123 2
                    name2 345 2
                    name2 345 3
                    name2 345 1

                    result:
                    name1 123 1
                    name1 123 2
                    name1 123 3
                    name2 345 1
                    name2 345 2
                    name2 345 3

                    VRoninV Offline
                    VRoninV Offline
                    VRonin
                    wrote on last edited by
                    #13

                    @leinad said in How to sort QList<QList<QVariant>>:

                    For some reason QStandardItemModel handles this all by itself

                    It doesn't. It probably just uses std::stable_sort instead of std::sort.

                    In any case this case is trivial, the comparison function can take care of it.
                    Using your example:

                    void MyModel::sort(int column, Qt::SortOrder order = Qt::AscendingOrder){
                    emit layoutAboutToBeChanged({QModelIndex()}, QAbstractItemModel::VerticalSortHint);
                    std::sort(list.begin(),list.end(),[column,order](const QList<QVariant>& a, const QList<QVariant>& b)->bool{
                    const auto aV = a.at(column);
                    const auto bV = b.at(column);
                    if(order == Qt::AscendingOrder)
                    return aV==bV ? aV<bV : a.at(2)<b.at(2);
                    return aV==bV ? aV>bV : a.at(2)>b.at(2);
                    });
                    emit layoutChanged({QModelIndex()}, QAbstractItemModel::VerticalSortHint);
                    }
                    

                    "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                    ~Napoleon Bonaparte

                    On a crusade to banish setIndexWidget() from the holy land of Qt

                    1 Reply Last reply
                    3
                    • L Offline
                      L Offline
                      leinad
                      wrote on last edited by
                      #14

                      Thank you! I'll try it.

                      1 Reply Last reply
                      0
                      • L Offline
                        L Offline
                        leinad
                        wrote on last edited by
                        #15

                        @VRonin said in How to sort QList<QList<QVariant>>:

                        mit layoutAboutToBeChanged({QModelIndex()}, QAbstractItemModel::VerticalSortHint);
                        std::sort(list.begin(),list.end(),[column,order](const QList<QVariant>& a, const QList<QVariant>& b)->bool{
                        const auto aV = a.at(column);
                        const auto bV = b.at(column);
                        if(order == Qt::AscendingOrder)
                        return aV==bV ? aV<bV : a.at(2)<b.at(2);
                        return aV==bV ? aV>bV : a.at(2)>b.at(2);
                        });
                        emit layoutChanged({QModelIndex()}, QAbstractItemModel::VerticalSortHint);

                        Unfortunately this does not work.
                        According to the code you have we don't sort on column at all. We first have to sort on column and once that is done, then we resort all duplicates of column values to some other column.

                        VRoninV 1 Reply Last reply
                        0
                        • L leinad

                          @VRonin said in How to sort QList<QList<QVariant>>:

                          mit layoutAboutToBeChanged({QModelIndex()}, QAbstractItemModel::VerticalSortHint);
                          std::sort(list.begin(),list.end(),[column,order](const QList<QVariant>& a, const QList<QVariant>& b)->bool{
                          const auto aV = a.at(column);
                          const auto bV = b.at(column);
                          if(order == Qt::AscendingOrder)
                          return aV==bV ? aV<bV : a.at(2)<b.at(2);
                          return aV==bV ? aV>bV : a.at(2)>b.at(2);
                          });
                          emit layoutChanged({QModelIndex()}, QAbstractItemModel::VerticalSortHint);

                          Unfortunately this does not work.
                          According to the code you have we don't sort on column at all. We first have to sort on column and once that is done, then we resort all duplicates of column values to some other column.

                          VRoninV Offline
                          VRoninV Offline
                          VRonin
                          wrote on last edited by VRonin
                          #16

                          I just inverted the 2 siders of :, it's trivial to fix:

                          void MyModel::sort(int column, Qt::SortOrder order = Qt::AscendingOrder){
                          emit layoutAboutToBeChanged({QModelIndex()}, QAbstractItemModel::VerticalSortHint);
                          std::sort(list.begin(),list.end(),[column,order](const QList<QVariant>& a, const QList<QVariant>& b)->bool{
                          const auto aV = a.at(column);
                          const auto bV = b.at(column);
                          if(order == Qt::AscendingOrder)
                          return aV==bV ?  a.at(2)<b.at(2) : aV<bV;
                          return aV==bV ? a.at(2)>b.at(2) : aV>bV;
                          });
                          emit layoutChanged({QModelIndex()}, QAbstractItemModel::VerticalSortHint);
                          }
                          
                          

                          "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                          ~Napoleon Bonaparte

                          On a crusade to banish setIndexWidget() from the holy land of Qt

                          1 Reply Last reply
                          1

                          • Login

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • Users
                          • Groups
                          • Search
                          • Get Qt Extensions
                          • Unsolved