LINUX.ORG.RU

Qt qsort сортировка списка

 , qsort, ,


0

1

Доброго времени суток! Встал передо мной вопрос сортировки списка. Прочитал докумментацию, нашел простейшую реализацию:

QList<int> list;
    list << 33 << 12 << 68 << 6 << 12;
    qSort(list.begin(), list.end());

Однако элементы моего списка не простые данные, а объекты класса. Допустим, у них есть поля типа Qstring, int и т.п. Как отсортировать список по этим значениям?

Заранее огромное спасибо


В классе переопределить операторы сравнения.

timon-ltv
()

Определить для класса operator<().

Elyas ★★★★★
()
Ответ на: комментарий от wota

Огромное спасибо за ответ. Пытаюсь сделать, как Вы написали:

  QList<MyClass> list; // MyClass{int a, QString b}

    list<<MyClass(5, QString("1212"));
    list<<MyClass(15, QString("12"));
    list<<MyClass(3, QString("1212"));
    list<<MyClass(15, QString("12"));
    list<<MyClass(24, QString("1212"));
    list<<MyClass(105, QString("12"));
    list<<MyClass(1, QString("12"));


    QListIterator<MyClass> i(list);
     i.toFront();
     while (i.hasNext())
     {
         qDebug() << i.next().a; //output a-variable in MyClass
     }

     qDebug()<<"-------------------------";

     qSort(list.begin(), list.end(), [](MyClass& a, MyClass& b) { return a.a < b.a; } );

выдается ошибка: error: no matching function for call to 'qSort(QList<MyClass>::iterator, QList<MyClass>::iterator, main(int, char**)::<lambda(MyClass&, MyClass&)>)

Может я суть не уловил?

gwyllum
() автор топика
Ответ на: комментарий от gwyllum

QMAKE_CXXFLAGS += -std=c++11

тогда собирается.

Но поле MyClass::a должно быть public для такой конструкции, что не очень хорошо.

grondek
()
Ответ на: комментарий от wota

Это конечно круто, но шибко новый стандарт. ЛУчше пока что писать по-старинке. Сделать отдельную функцию LessThan и т.д.

grondek
()
Ответ на: комментарий от grondek

Это конечно круто, но шибко новый стандарт. ЛУчше пока что писать по-старинке. Сделать отдельную функцию LessThan и т.д.

Или статичную функцию класса.

UVV ★★★★★
()
Ответ на: комментарий от UVV

Я пробовал и так

bool caseInsensitiveLessThan(const MyClass &s1, const MyClass &s2)
{
    return (s1.a() < s2.a());
}


int main()
{
//.....
 qSort(list.begin(), list.end(), caseInsensitiveLessThan);
}

error: 'caseInsensitiveLessThan' was not declared in this scope

Я подозреваю, что что-то упускаю. Потому как с QStringList это все работает

gwyllum
() автор топика
Ответ на: комментарий от gwyllum

Вот тебе первые 2 человека посоветовали сделать простую и понятную вещь, не привязанную к новому стандарту...

Но ты выбрал самый неочевидный для новичка метод. Зачем?

solovey ★★
()
Ответ на: комментарий от gwyllum
class MyClass {
  ...
  bool operator <(const MyClass &other) {
    ...
  }
  ...
};

int main () {
  QList<MyClass> list;
  /*add items to list here*/
  qSort(list.begin(), list.end());
}

Как-то так должно работать... Я, естественно, не проверял.

solovey ★★
()
Последнее исправление: solovey (всего исправлений: 1)
Ответ на: комментарий от gwyllum

error: 'caseInsensitiveLessThan' was not declared in this scope

у тебя caseInsensitiveLessThan в другом файле находится?
вообще, если хочешь, чтобы тебе быстро помогли, выдавай законченный минимальный вариант кода, с которым у тебя возникают проблемы
а то по кускам догадываться никому неохота

dt1 ★★
()
Ответ на: комментарий от solovey

Пробовал как Вы говорите

bool MyClass::operator <(const MyClass &other)
{
    return ( this->a < other.a);
}

..\..\..\..\5.0.1\mingw47_32\include/QtCore/qalgorithms.h:160:24: error: passing 'const MyClass' as 'this' argument of 'bool MyClass::operator<(const MyClass&)' discards qualifiers [-fpermissive]

gwyllum
() автор топика
Ответ на: комментарий от dt1

нет, в том же - main.cpp

суть в том, что в qSort(list.begin(), list.end(), caseInsensitiveLessThan) функция находится без скобок. С QStringList это работает, а тут - не срабатывает.

Прошу прощения, выдаю код:


//myclass.h
class MyClass
{
public:
    MyClass();

    MyClass(int a, QString b);

    bool operator <(const MyClass &other);


    int a;

    QString b;

};


//myclass.cpp
MyClass::MyClass()
{
}


MyClass::MyClass(int a, QString b)
{
    this->a=a;
    this->b=b;
}




//main.cpp

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);


    QList<MyClass> list;

    list<<MyClass(5, QString("1212"));
    list<<MyClass(15, QString("12"));
    list<<MyClass(3, QString("1212"));
    

  qSort(list.begin(), list.end(), caseInsensitiveLessThan );

}

bool caseInsensitiveLessThan(const MyClass &s1, const MyClass &s2)
{
    return (s1.a() < s2.a());
}

gwyllum
() автор топика
Ответ на: комментарий от solovey

Огромное спасибо Вам за помощь. Извините пожалуйста, что я туплю)

Я сделал как вы и говорили:

//myclass.cpp
bool MyClass::operator < (const MyClass &other) const
{
    return ( a < other.a);
}

//main.cpp
//....
 qSort(list.begin(), list.end());

теперь никаких ошибок не выдается, однако если я делаю вывод после, то результат не меняется:

 i.toFront();
      while (i.hasNext())
      {
          qDebug() << i.next().a;
      }
gwyllum
() автор топика
Ответ на: комментарий от gwyllum

Я немного не дописал... Вот так работает:

#include <QApplication>
#include <QDebug>

class Test {
public:
    int a;
    QString b;
    
    
    Test () : a(0), b("") 
    {}
    Test (int aa, QString bb) : a(aa), b(bb) 
    {}
    
    bool operator <(const Test &t2) const{
        return a < t2.a;
    }
};

int main (int argc, char **argv) {
    QApplication app (argc, argv);
    Test t1(1, "lol");
    Test t2(2, "lol1");
    QList<Test> list;
    list << t2 << t1;
    qDebug() << "before sort";
    foreach (Test t, list) {
        qDebug() << t.a << t.b;
    }
    qSort (list.begin(), list.end());
    qDebug() << "after sort";
    foreach (Test t, list) {
        qDebug() << t.a << t.b;
    }
    return 0;
}

solovey ★★
()
Ответ на: комментарий от solovey

Огромное Вам спасибо!!! Все на самом деле работает. Я попытался найти ошибку в своем примере и вот что получилось: я заменил

      i.toFront();
      while (i.hasNext())
      {
          qDebug() << i.next().a;
      }

на

 foreach (MyClass c, list)
    {

        qDebug()<<c.a;

    }

и у меня тоже начало выводить сортированный список. Что наводит на определенные мысли - получается при qsort старый итератор уже некорректно работает.

Я вставил объявление итератора после сортировки(в первый раз выводил Вашим методом)

 qSort(list.begin(), list.end());

      QListIterator<MyClass> i(list);


      i.toFront();
      while (i.hasNext())
      {
          qDebug() << i.next().a;
      }

в этом случае все заработало корректно. интересно)

спасибо огромное Вам еще раз. от всей души благодарен :)

gwyllum
() автор топика
Ответ на: комментарий от solovey

Прошу прощения, еще один вопрос всплыл - если мне нужно сортировать по нескольким полям - т.е. в одном случае мне нужно отсортировать по имени, в другом - по номеру, в третьем - по дате рождения или телефону; как в этом случае перегружать оператор?

gwyllum
() автор топика
Ответ на: комментарий от gwyllum

ну вот теперь понятно, откуда берется ошибка
нужно объявить caseInsensitiveLessThan до main

dt1 ★★
()
Ответ на: комментарий от gwyllum

да никак, нужно функции или функторы использовать, можешь забыть про первых двух советчиков :)

dt1 ★★
()
Ответ на: комментарий от gwyllum

Я бы для такого случая написал свой метод, который пробегается по QList<Test> и сравнивает нужные поля, в зависимости от того, что ему передано на вход...

Еще вариант - сделать много caseInsensitiveLessThan функций и написать обертку, в которую подсовывать вызов нужной функции...

Хотя я не уверен, что это будут оптимальные решения

solovey ★★
()
Ответ на: комментарий от gwyllum

Один из вариантов: делаем функтор. И при его конструировании говорим, по какому полю сортировать.

grondek
()
Ответ на: комментарий от gwyllum
#include <QtAlgorithms>
#include <QDebug>

struct Foo
{
  int number;
  QString name;
};

inline QDebug operator<< (QDebug d, const Foo& foo)
{
  d << foo.number << " " << foo.name;
  return d;
}

struct FooLessNumber
{
  bool operator()(const Foo& lhs, const Foo& rhs) const
  {
    return lhs.number < rhs.number;
  }
};

struct FooLessName
{
  bool operator()(const Foo& lhs, const Foo& rhs) const
  {
    return lhs.name < rhs.name;
  }
};

int main(int argc, char *argv[])
{
    Foo a = {3, "A"};
    Foo b = {2, "B"};
    Foo c = {1, "C"};
    QList<Foo> list;
    list << a << b << c;

    qSort(list.begin(), list.end(), FooLessNumber());
    qDebug() << list;

    qSort(list.begin(), list.end(), FooLessName());
    qDebug() << list;

    return 0;
}
bjorn
()
Ответ на: комментарий от gwyllum

С другой стороны, постоянно пересортировывать большой список - долго. В таком случае мжно пожертвовать немного памяти и понаделать QMap< тип поля сортировки, указатель на объект > столько штук, сколько надо. И при изменении соответствующего поля добавляься в соответствующий словарь.

grondek
()
Ответ на: комментарий от grondek

Например:

class MyClass
{
private:
 QString a;
 quint32 b;

static QMap< QString, MyClass*> myclass_a_map;
static QMap< quint32, MyClass*> myclass_b_map;
public:
 MyClass() {}
 virtual ~MyClass(){}
};


Соответственно сделать сеттеры-геттеры для полей и корректно обрабатывать их изменение. Ну и в деструкторе класса обрабатывать удаление объекта.

Вот такой вот вариант.

grondek
()
Ответ на: комментарий от grondek

Соответственно сделать сеттеры-геттеры для полей и корректно обрабатывать их изменение Вот такой вот вариант.

Фееричненький вариант, даже в случае однопоточной программы.

Begemoth ★★★★★
()
28 мая 2013 г.

qsort сложная сортировка - простые решения

http://www.qtcentre.org/archive/index.php/t-9485.html - тут есть ответ. Фишка в том что функция сортировки должна быть НЕ ЧЛЕНОМ класса(пишется сразу после инклудов и в хедере объявления не требует). То есть из этого примера

bool compare(const QString &s1, const QString &s2)//not member of class
{
    return s1.toLower() < s2.toLower();
}

int doSomething()//anywhere in class
{
    QStringList list;
    list << "AlPha" << "beTA" << "gamma" << "DELTA";
    qStableSort(list.begin(), list.end(), caseInsensitiveLessThan);
    // list: [ "AlPha", "beTA", "DELTA", "gamma" ]
}
- это функция compare;

Если же решать лямбдами все еще проще -

 QList<QPushButton*> listT = ui->stat__p_mButt->findChildren<QPushButton*>();//get list QPushButton's
    qSort(listT.begin(), listT.end(),[](const QObject* a, const QObject* b )//sorting
{
return  a->objectName() <  b->objectName();//lambda expression
});

^^^ -пример из работающей программы.

anonymous
()
27 ноября 2014 г.
Ответ на: комментарий от wota

Наконец-то я встретил практическое применение лямбд в плюсах :)

(На самом деле я впервые столкнулся с ними, когда мой gcc на предыдущем дебиане не пожелал откомпилировать LeechCraft, но автор Личкрафта известен своей приверженностью к неординарным решениям, и тогда я этому значения не придал.)

hobbit ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.