Russian Qt Forum
Ноябрь 26, 2024, 14:28 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: QList<t> удаление одинаковых элементов QList / QSet  (Прочитано 20421 раз)
daimon
Гость
« : Ноябрь 17, 2009, 00:43 »

Есть список из интов. Как удалить повторяющиеся элементы через алгоритмы?
« Последнее редактирование: Ноябрь 17, 2009, 11:55 от daimon » Записан
Павел_F.
Гость
« Ответ #1 : Ноябрь 17, 2009, 07:40 »

Можно:
1) отсортировать список(  алгоритмов полно, выбирайте что нравится)
2) Бежать итератором по списку и удалять если текущий равен предыдущему.
3) Учесть что итераторы, вроде как, портятся при удалении элементов ( хотя могу ошибаться).
Тогда все элементу будут уникальными.
Если сортировать не надо, а надо сохранить последовательность то
1) сделать новый список
2) Бежать итератором по исходному списку и, если элемент не содержится в новом списке, добавлять в новый список ( проверить можно bool QList::contains ( const T & value ) const).
3) Подменить исходный список новым
По поводу скорости вариантов рассуждать уже вам.
Если подумать то можно и лучше придумать.
« Последнее редактирование: Ноябрь 17, 2009, 07:46 от Павел_F. » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Ноябрь 17, 2009, 08:15 »

Код:
template <class T> 
void RemoveListDup( QList <T> & lst )
{
  QSet <T> qs;
  int i, place = 0, limit = lst.size();
  for (i = 0; i < limit; ++i) {
    T & val = lst[i];
    if (qs.contains(val)) continue;
    qs.insert(val);
    if (i != place) lst[place] = val;
    ++place;
  }
  lst.erase(lst.begin() + place, lst.end());
}
Записан
Павел_F.
Гость
« Ответ #3 : Ноябрь 17, 2009, 08:33 »

Вот и пример второго варианта ( не совсем, конечно, но суть таже). Но итератором бегать будет существенно быстрее чем в цикле брать элемент по номеру. Я бы использовал именно его. Да и в случае использования const_iterator QSet::insert ( const T & value ) не вижу смысла использовать contains.
Из справки:
const_iterator QSet::insert ( const T & value )
Inserts item value into the set, if value isn't already in the set, and returns an iterator pointing at the inserted item.
Значит в место:
Код:
if (qs.contains(val)) continue;
    qs.insert(val);
Можно написать:
Код:
if( qs.insert(val) != qs.end()) continue;
Что уберет весьма затратную contains.
Хотя все вопросы о скорости зависят от нужд и "структуры" содержимого списка.
« Последнее редактирование: Ноябрь 17, 2009, 08:46 от Павел_F. » Записан
daimon
Гость
« Ответ #4 : Ноябрь 17, 2009, 11:37 »

Можно:
1) отсортировать список(  алгоритмов полно, выбирайте что нравится)
2) Бежать итератором по списку и удалять если текущий равен предыдущему.
3) Учесть что итераторы, вроде как, портятся при удалении элементов ( хотя могу ошибаться).
Тогда все элементу будут уникальными.
Если сортировать не надо, а надо сохранить последовательность то
1) сделать новый список
2) Бежать итератором по исходному списку и, если элемент не содержится в новом списке, добавлять в новый список ( проверить можно bool QList::contains ( const T & value ) const).
3) Подменить исходный список новым
По поводу скорости вариантов рассуждать уже вам.
Если подумать то можно и лучше придумать.
Самый простой вариант это пушать элемент, проверяя его на вместимость в списке (если нет - то вставлять в список)
Спасибо за ответы
Записан
Павел_F.
Гость
« Ответ #5 : Ноябрь 17, 2009, 11:44 »

Самый простой вариант это пушать элемент, проверяя его на вместимость в списке (если нет - то вставлять в список)
Спасибо за ответы
Правильно заданный вопрос содержит половину ответа. Вы  писали "есть список интов", а раз список уже есть я бы даже и не предположил что есть шанс влиять на алгоритмы создания списка. Но раз такой шанс... Зачем тогда QList, раз хранить надо только уникальные элементы? QSet, вроде, тут выглядит более умесным...
Записан
daimon
Гость
« Ответ #6 : Ноябрь 17, 2009, 11:49 »

Самый простой вариант это пушать элемент, проверяя его на вместимость в списке (если нет - то вставлять в список)
Спасибо за ответы
Правильно заданный вопрос содержит половину ответа. Вы  писали "есть список интов", а раз список уже есть я бы даже и не предположил что есть шанс влиять на алгоритмы создания списка. Но раз такой шанс... Зачем тогда QList, раз хранить надо только уникальные элементы? QSet, вроде, тут выглядит более умесным...
Преимущества QSet от QList?
« Последнее редактирование: Ноябрь 17, 2009, 12:09 от daimon » Записан
Павел_F.
Гость
« Ответ #7 : Ноябрь 17, 2009, 13:39 »

Преимущества QSet от QList?
Из справки по Qt.
Цитировать
Detailed Description
The QList class is a template class that provides lists.
QList<T> is one of Qt's generic container classes. It stores a list of values and provides fast index-based access as well as fast insertions and removals.
QList класс представляет собой шаблон класса списков.
является одним из универсальных классов. Хранит список значений и обеспечивает быстрый доступ, а также быструю вставку и удаление.

Цитировать
The QSet class is a template class that provides a hash-table-based set.

QSet<T> is one of Qt's generic container classes. It stores values in an unspecified order and provides very fast lookup of the values. Internally, QSet<T> is implemented as a QHash.
Класс QSet это шаблон класса, который представляет собой хэш-таблицу основе набора.
Она хранит значения в неопределенном порядке и обеспечивает очень быстрый поиск значений.

Т.е. получается что они выполняют разные функции.
У QSet нет, как такового, доступа по индексу.
В QSet изначально нельзя добавить два одинаковых элемента. Если insert'том добавлять элемент который уже есть то он его не добавит и вернет итератор указывающий элемент, который уже есть в QSet ( фактически это и будет индекс элемента).


Если надо хранить набор значений то QSet. Если надо классический список то QList. Я не знаю вашей задачи и отвечаю согласно вопросу и тому как я этот вопрос понял.
Записан
daimon
Гость
« Ответ #8 : Ноябрь 17, 2009, 13:46 »

Преимущества QSet от QList?
Из справки по Qt.
Цитировать
Detailed Description
The QList class is a template class that provides lists.
QList<T> is one of Qt's generic container classes. It stores a list of values and provides fast index-based access as well as fast insertions and removals.
QList класс представляет собой шаблон класса списков.
является одним из универсальных классов. Хранит список значений и обеспечивает быстрый доступ, а также быструю вставку и удаление.

Цитировать
The QSet class is a template class that provides a hash-table-based set.

QSet<T> is one of Qt's generic container classes. It stores values in an unspecified order and provides very fast lookup of the values. Internally, QSet<T> is implemented as a QHash.
Класс QSet это шаблон класса, который представляет собой хэш-таблицу основе набора.
Она хранит значения в неопределенном порядке и обеспечивает очень быстрый поиск значений.

Т.е. получается что они выполняют разные функции.
У QSet нет, как такового, доступа по индексу.
В QSet изначально нельзя добавить два одинаковых элемента. Если insert'том добавлять элемент который уже есть то он его не добавит и вернет итератор указывающий элемент, который уже есть в QSet ( фактически это и будет индекс элемента).


Если надо хранить набор значений то QSet. Если надо классический список то QList. Я не знаю вашей задачи и отвечаю согласно вопросу и тому как я этот вопрос понял.
Как я понял QSet менее трудоемкий класс и более производителней
Записан
Павел_F.
Гость
« Ответ #9 : Ноябрь 17, 2009, 13:48 »

Не совсем... Он просто другой. А трудоемкость и производительность зависит от того что от него требовать. Если пытаться сделать что то типа QList::at( int index) то QSet окажется медленнее, если точнее то там такого просто нет и надо велосипед изобретать. А если тебе надо что то найти в своей кучке то тогда QSet быстрее.
« Последнее редактирование: Ноябрь 17, 2009, 13:53 от Павел_F. » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Ноябрь 17, 2009, 14:12 »

Вот и пример второго варианта ( не совсем, конечно, но суть таже). Но итератором бегать будет существенно быстрее чем в цикле брать элемент по номеру.
....
Можно написать:
Код:
if( qs.insert(val) != qs.end()) continue;
Что уберет весьма затратную contains.
Оператор [] "достаточно быстр" и экономить на нем по-моему неразумно. Вызов contains должен быть быстрее insert (добавление в контейнер всегда тяжелее). Обойтись без contains - я бы не рисковал, судя по исходникам нельзя сказать что QSet::insert "ничего не делает если такой элемент уже есть".

Полностью согласен что к задаче надо подходить конкретно в зависимости от нужд/контекста.

QList класс представляет собой шаблон класса списков.
является одним из универсальных классов. Хранит список значений и обеспечивает быстрый доступ, а также быструю вставку и удаление.
QList - никакой не "список", это просто массив указателей. Так что искать в нем придется прямым перебором. "Быстрая вставка и удаление" - здесь имеется ввиду 2 вещи:

- быстрое добавление в начало/конец (там зарезервированы места)

- при вставке в середину указатель на новый элемент вставляется в массив указателей. Это гораздо дешевле чем вставка напр. для std::vector - но все-таки такая операция может двигать в памяти много данных и вызывать перераспределения памяти. Поэтому надо использовать возможность избежать удаления/вставки (как в этом примере).
Записан
Павел_F.
Гость
« Ответ #11 : Ноябрь 17, 2009, 14:28 »

Оператор [] "достаточно быстр" и экономить на нем по-моему неразумно. Вызов contains должен быть быстрее insert (добавление в контейнер всегда тяжелее). Обойтись без contains - я бы не рисковал, судя по исходникам нельзя сказать что QSet::insert "ничего не делает если такой элемент уже есть".

Если получится что список большой а повторяющихся элементов очень мало то на контайнс сьэкономить можно существенно. Но это уже решать тому, кто знает что это за список и зачем он ему, что я не один раз повторил. Про [] в целом согласен.
QList - никакой не "список", это просто массив указателей.

Массив указателей с методами это и есть список.
Цитата: ru.wikipedia.org
Спи́сок — конечное, возможно пустое множество данных (элементов) различной природы, имеющее определённый смысл для решаемой задачи. В качестве элементов множества (списка) могут выступать любые другие элементы данных, в том числе и сами списки.
Так что искать в нем придется прямым перебором. "Быстрая вставка и удаление" - здесь имеется ввиду 2 вещи:

- быстрое добавление в начало/конец (там зарезервированы места)

- при вставке в середину указатель на новый элемент вставляется в массив указателей. Это гораздо дешевле чем вставка напр. для std::vector - но все-таки такая операция может двигать в памяти много данных и вызывать перераспределения памяти. Поэтому надо использовать возможность избежать удаления/вставки (как в этом примере).
Согласен.
« Последнее редактирование: Ноябрь 17, 2009, 14:35 от Павел_F. » Записан
daimon
Гость
« Ответ #12 : Ноябрь 17, 2009, 14:42 »

Я использую QList для хранения номеров колонок, которые нужно будет выделить и часто пользуюсь [] -- ? значит лучше не использовать QSet
Записан
Павел_F.
Гость
« Ответ #13 : Ноябрь 17, 2009, 14:54 »

Сколько их, если по максимуму оценивать? Учитывая что вы в соседней теме спрашиваете что то про QTableWidget, думаю не много. Я бы вообще сделал массив для этого и не трогал списки/ кучи/ хеш таблицы. Но это личное дело каждого.
Записан
daimon
Гость
« Ответ #14 : Ноябрь 17, 2009, 15:07 »

Сколько их, если по максимуму оценивать? Учитывая что вы в соседней теме спрашиваете что то про QTableWidget, думаю не много. Я бы вообще сделал массив для этого и не трогал списки/ кучи/ хеш таблицы. Но это личное дело каждого.
QList использую потому, что знаю потом его размер и его можна пушать
Изначально я не знаю размер списка, а под масив сразу нужно выделить память
« Последнее редактирование: Ноябрь 17, 2009, 15:13 от daimon » Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.132 секунд. Запросов: 23.