Russian Qt Forum

Qt => Общие вопросы => Тема начата: SABROG от Июнь 07, 2007, 15:42



Название: ::iterator, ::const_iterator
Отправлено: SABROG от Июнь 07, 2007, 15:42
Вопрос не столько по Qt, сколько по самому программированию на C++.
Есть QVariantList (QList<QVariant>). В нем список уникальныйх intовых значений. Хочу убрать из листа несколько или все значения не подходящие мне по условию. Чтобы на выходе лист содержал либо все эти значений, либы все без удаленных, либо был пустым. Но я не хочу создавать второй (временный) лист. Если цикл оформлять через .size() и удалять ненужные значения через removeAt(i), то цикл вероятно будет выполняться, скажем, раз 30, хотя под конец список может быть уже и пустым, а значит я получу exception. Если делать через ::iterator, то цикл выполняется с одним и тем же указателем ровно такое количество раз, сколько было удалено значений. Т.е. я удаляю скажем 3 значения, цикл выполняет 3 пустых итераций на следующем значении с одним и тем же указателем. Но у меня в цикле идут Selectы к базе, поэтому мне совсем не кстати, скажем 200 бесполезных запросов. Пытался сделать через const_iterator, но все тоже самое. Видимо я не совсем понимаю логику его работы.


Название: ::iterator, ::const_iterator
Отправлено: Alex Forth от Июнь 07, 2007, 16:09
Покури мануал по

template <class ForwardIterator, class Predicate>
ForwardIterator remove_if(ForwardIterator first, ForwardIterator last,         Predicate pred);

из STL


Название: ::iterator, ::const_iterator
Отправлено: Sergeich от Июнь 07, 2007, 16:14
Код:
	QVariantList l;
...
QVariantList::iterator it = l.begin();
while ( it != l.end() ) {
if ( needRemove(*it) )
it = l.erase( it );
else
++it;
}


Название: ::iterator, ::const_iterator
Отправлено: SABROG от Июнь 07, 2007, 16:24
Alex Forth, спасибо за вектор.
Sergeich, была тоже мысль с увеличением указателя итератора.

Покурил Assistant, вот что нашел:

Код:

 QMutableListIterator<int> i(list);
 while (i.hasNext()) {
     int val = i.next();
     if (val < -32768 || val > 32767)
         i.remove();
 }


Название: ::iterator, ::const_iterator
Отправлено: Tonal от Июнь 07, 2007, 17:53
Код:

template<class Pred>
inline void remove(QVariantList& l, const Pred& needRemove) {
  l.erase(std::remove_if(l.begin(), l.end(), needRemove), l.end());
}


Название: ::iterator, ::const_iterator
Отправлено: SABROG от Июнь 07, 2007, 18:11
Tonal, ты бы хоть пояснил что за шаблончик такой интересный.
Я так понимаю это шаблон для встраиваемой функции remove, которой передается ссылка на лист и ссылка на объект любого типа, в котором содержится некоторое значение. Если это значение встречается в промежтке от begin до end, то на него возвращается итератор, который и уничтожается eraseом в промежутке от индекса найденного итератора до конца (end) ? Теперь глупый вопрос, этот код кросплатформенный ?

Я так понимаю этот код аналогичен этому (взято из Assistant'a):

Код:

int QList::removeAll ( const T & value )
Removes all occurrences of value in the list and returns the number of entries removed.
Example:
 QList<QString> list;
 list << "sun" << "cloud" << "sun" << "rain";
 list.removeAll("sun");
 // list: ["cloud", "rain"]
This function requires the value type to have an implementation of operator==().


Только это несколько не то, что мне надо. В листе все элементы уникальны. Мне надо брать каждый, делать запрос в базу или к другому массиву и сравнивать с ним, если есть пересечение, то удалять. Но в принципе я думаю справлюсь с этим, всего-лишь вручную увеличивая итератор после удаления, чтобы исключить пустые циклы.


Название: ::iterator, ::const_iterator
Отправлено: Tonal от Июнь 07, 2007, 19:30
Использовать элементарно.
Пишем функцию needRemove, который принимает параметр типа QVariant возвращает истину если его надо удалить.
Передаём её в remove вторым параметром. Первым лист над которым издеваемся. ;-)
Код:

bool needRemove(const QVariant& val) {
  // здесь выполняем твои запросы, и пересечения.
  //Возвращаем true если элемент нужно удалить
}


void doWork(QVariantList& list) {
  //Здесь происходит вызов needRemove для каждого элемента
  //списка, и те, для которых вернулось true удаляються
  remove(list, needRemove);
}


Название: ::iterator, ::const_iterator
Отправлено: SABROG от Июнь 07, 2007, 21:03
Пфф, что-то странное. Я думал, что в remove передается значение вторым параметром, а не ссылка на функцию, которая true возрващает ? Не будет ли так, что remove_if будет искать булевые значения true или false :) ?


Название: ::iterator, ::const_iterator
Отправлено: Tonal от Июнь 08, 2007, 08:15
Нет. Ты перепутал с remove.
remove_if будет вызывать функцию для каждого значения, и по её результату решать что делать.

P.S. Почитай про STL - он всё таки часть языка, на котором ты пишешь. ;-)


Название: ::iterator, ::const_iterator
Отправлено: SABROG от Июнь 08, 2007, 09:48
Почитал http://www.sgi.com/tech/stl/

Эти "предикаты" меня в тупик ставят.

Код, порой, так усложняют, не понятно, что на самом деле происходит. Например свойства компонентов в delphi и bcb, думаешь, что записываешь в переменную, а на поверку оказывается, что вызываются функции типа setValue, getValue, где может быть все, что угодно, да еще перегрузка операторов. Все спотыкаюсь о камни подводные и спотыкаюсь. Об STL что-то маловато серьезных, русскоязычных, статей находится.


Название: ::iterator, ::const_iterator
Отправлено: Tonal от Июнь 09, 2007, 09:57
Возьми "Язык Программирования С++" 3 Страуструпа.
Очень понятно и доступно изложенно. ;-)

А насчёт усложнений - пиши на асемблере или на форте, только без макросов.
Как раз получается - что вижу то и произойдёт - этакое чукча-программирование. ;-)


Название: ::iterator, ::const_iterator
Отправлено: SABROG от Июнь 09, 2007, 11:42
Цитата: "Tonal"
Возьми "Язык Программирования С++" 3 Страуструпа.
Очень понятно и доступно изложенно. ;-)

А насчёт усложнений - пиши на асемблере или на форте, только без макросов.
Как раз получается - что вижу то и произойдёт - этакое чукча-программирование. ;-)


Ассемблер - первый язык который я выучил. Я на нем писал года 4, прошел дорогу от DOS'a с Turbo Assemblerом, плавно переходя с .com приложений до win16, потом пересел на MASM32 с туториалами IcZeilon'a, далее выбор был сделан в пользу Fasm32, пописал на нем утилиты различные типа тренеров, кряков и saveeditоров. Потом пересел на linux и снова пописал утилитки на fasm32 только уже используя GTK. Дальше решил понять что такое Perl, написал на нем IRC бота, который коннектился к MySQL базе и цеплял ответы на вопросы "Викторины", а потом уже пришел ко мне C++. И я вот уже года 2 пытаюсь в него въехать искренне не понимая, почему нельзя обойтись одними типами данных - бит, байт, байт*n

Эх хорошие были времена в Fido в конверенции RU.ASM, частенько решали задачки по оптимизации кода, как по скорости так и по размеру.