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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Как сделать кратко/красиво  (Прочитано 7825 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Март 15, 2011, 16:24 »

Добрый день

Есть структура
Код
C++ (Qt)
struct CMesh {
void Append( const CMesh & );  // импорт данных
void Clear( void );  // освобождает память занимаемую данными
CShape * CreateShape( void ) const;  // создает др. (внешнюю) структуру
 
// данные
float mFriction;
//... контейнеры и.т.п
};
typedef std::vector <CMesh *> TMeshPtrVec;
typedef std::vector <CShape *> TShapePtrVec;
 

Теперь надо написать ф-цию
Код
C++ (Qt)
// static
void CMesh::CreateShapes( TMeshPtrVec & mesh, TShapePtrVec & shape )
{
...
}
 
которая создает из элементов входного mesh вектора CShape * и помещает их в выходной вектор shape. но с одним условием: входные элементы с одинаковым mFriction должны быть "слиты" (с помощью методов Append и Clear) и только одно CShape создано для таких. Примеры: все элементы mesh имеют одинаковый mFriction - значит всего 1 новый элемент добавлен в shape. И наоборот - все mFriction разные - значит для каждого надо создать CShape.

Вопрос в том как это сделать красиво/элегантно - у меня получается коряво  Улыбающийся

Спасибо
« Последнее редактирование: Март 15, 2011, 16:26 от Igors » Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #1 : Март 15, 2011, 17:05 »

Я бы посмотрел в сторону алгоритма find_if, в сочетании с count_if

Или вот, пожалуй, лучше всего подходит под это дело:
http://www.cplusplus.com/reference/algorithm/unique_copy/
 
« Последнее редактирование: Март 15, 2011, 17:53 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Март 15, 2011, 19:38 »

Я бы посмотрел в сторону алгоритма find_if, в сочетании с count_if

Или вот, пожалуй, лучше всего подходит под это дело:
http://www.cplusplus.com/reference/algorithm/unique_copy/
Хммм...  "прошу исполнить"  Улыбающийся
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #3 : Март 15, 2011, 20:17 »

Ну вот, например:
Код
C++ (Qt)
bool myBinaryPredicate(CMesh* a, CMesh* b) {
   return (a->mFriction == b->mFriction);
}
 
bool compare (CMesh* a, CMesh* b) {
   return (a->mFriction < b->mFriction);
}
 
 
void CMesh::CreateShapes( TMeshPtrVec & mesh, TShapePtrVec & shape )
{
    TMeshPtrVec v = mesh;
    TMeshPtrVec::iterator it = unique_copy (mesh.begin(), mesh.end(), v.begin(), myBinaryPredicate);
    sort (v.begin(), it, compare);
    it=unique_copy (v.begin(), it, v.begin(), myBinaryPredicate);
    v.resize( it - v.begin());
/* v - теперь содержит указатели на CMesh c уникальными значениями mFriction */
/* Дальше все действия с ним..  */
}
 

Хотя я это не проверял)
« Последнее редактирование: Март 15, 2011, 20:38 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Март 15, 2011, 20:42 »

Хотя я это не проверял)
Та вижу что нет  Улыбающийся
Пусть первые 2 элемента имеют одинаковый ключ (mFriction). Тогда, если я правильно понимаю, unique_copy поместит в выходной вектор лишь первый из них, второй не будет долит к первому - а должен
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #5 : Март 15, 2011, 20:47 »

Хотя я это не проверял)
Та вижу что нет  Улыбающийся
Пусть первые 2 элемента имеют одинаковый ключ (mFriction). Тогда, если я правильно понимаю, unique_copy поместит в выходной вектор лишь первый из них, второй не будет долит к первому - а должен
В смысле долит? Этот код создаёт только вектор с указателями на уникальные mFriction.. Он ничё никуда не доливает)  

Если я правильно понимаю, то доливание одного вектора в другой, если у них одинаковые mFriction можно произвести в myBinaryPredicate...
« Последнее редактирование: Март 15, 2011, 20:50 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Март 15, 2011, 20:55 »

В смысле долит? Этот код создаёт только вектор с указателями на уникальные mFriction.. Он ничё никуда не доливает) 
Ну а зачем такой вектор нужен? Ведь задача объединить (с помощью Append) подходящие элементы и создать для них одну CShape.

Кстати о птичках: если уж создавать вектор уникальных, то не лучше ли сначала отсортировать, а затем один раз вызвать unique_copy (а то увлеклись списыванием  Улыбающийся)
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #7 : Март 15, 2011, 21:05 »

В смысле долит? Этот код создаёт только вектор с указателями на уникальные mFriction.. Он ничё никуда не доливает) 
Ну а зачем такой вектор нужен? Ведь задача объединить (с помощью Append) подходящие элементы и создать для них одну CShape.
Можно непосредственно в функции myBinaryPredicate "сливать" данные из одного (a) в другой (b) (с помощью Append), если они равны.

Цитировать
Кстати о птичках: если уж создавать вектор уникальных, то не лучше ли сначала отсортировать, а затем один раз вызвать unique_copy (а то увлеклись списыванием  Улыбающийся)

Можно, конечно) Я просто Вашу бдительность проверял))
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Март 15, 2011, 21:26 »

Можно непосредственно в функции myBinaryPredicate "сливать" данные из одного (a) в другой (b) (с помощью Append), если они равны.
Может даже это и будет работать (не знаю), но делать такие "масштабные" действия в ф-ции предназначенной просто для сравнения - никак не гуд.

Да и копирование вектора (с последующим resize) хорошего впечатления не производит. Нельзя сделать как-то "через голову", не слишком привлекая мутность STL?
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #9 : Март 15, 2011, 21:44 »

Можно непосредственно в функции myBinaryPredicate "сливать" данные из одного (a) в другой (b) (с помощью Append), если они равны.
Может даже это и будет работать (не знаю), но делать такие "масштабные" действия в ф-ции предназначенной просто для сравнения - никак не гуд.
Почему эт? Это всё равно придётся делать) Кстати, зачем тогда придумали ещё и объекты функций?
Правильно, для большей гибкости.

Цитировать
Да и копирование вектора (с последующим resize) хорошего впечатления не производит. Нельзя сделать как-то "через голову", не слишком привлекая мутность STL?
Да он всё равно локален и разрушится при выходе из функции.
Сколько там (в mesh) в среднем элементов планируется держать?

Если без этого временного вектора v, то тогда лучше использовать find_if, но это будет медленее и так кратко не думаю что получится. 
« Последнее редактирование: Март 15, 2011, 21:53 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Март 15, 2011, 22:02 »

Почему эт? Это всё равно придётся делать) Кстати, зачем тогда придумали ещё и объекты функций?
Правильно, для большей гибкости.
Мда, шансы убедить равны нулю  Улыбающийся Лучше расскажу как я сделал

Код
C++ (Qt)
bool CompareFriction( const CMesh * m0, const CMesh * m1 )
{
return m0->mFriction < m1->mFriction;
}
 
bool NextRange( const TMeshPtrVec & vec, size_t & beg, size_t & end )
{
if (end >= vec.size()) return false;
beg = end;
for (end = beg + 1; end < vec.size(); ++end)
 if (vec[end]->mFriction != vec[beg]->mFriction) break;
 
return true;
}
 
 
void CMesh::CreateShapes( TMeshPtrVec & mesh, TShapePtrVec & shape )
{
std::sort(mesh.begin(), mesh.end(), CompareFriction);
 
size_t beg, end = 0;
while (NextRange(vec, beg, end)) {
 for (size_t i = beg + 1; i < end; ++i) {
  vec[beg]->Append(*vec[i]);
  vec[i]->Clear();
 }
 shape.push_back(vec[beg]->CreateShape());
}
}
 
« Последнее редактирование: Март 15, 2011, 22:05 от Igors » Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #11 : Март 15, 2011, 22:35 »

Тогда как вариант:
Код
C++ (Qt)
class MyFunctor
{
public:
   CMesh * operator()(CMesh *a, CMesh *b) {
       if ((a->mFriction == b->mFriction) && (a->mFriction == m_unique_friction.back()) && m_tag)
      {
           a->Append(b);
           b->Clear();
           return a;
       }
        return 0;
   }
 
bool frictionIsContains(float f) {
   vector<double>::iterator it = find(m_unique_friction.begin(), m_unique_friction.end(), f);
   if (it != m_unique_friction.end()) {
       m_unique_friction.push_back(f);
       m_tag = true;
       return m_tag;
   }
    m_tag = false;
    return m_tag;
}
private:
vector<float> m_unique_friction;
bool m_tag;
};
 
void CMesh::CreateShapes( TMeshPtrVec & mesh, TShapePtrVec & shape )
{
   TMeshPtrVec::iterator it = mesh.begin();
   MyFunctor func;
    for (; it != mesh.end(); ++it) {
       if (!func.frictionIsContains((*it)->mFriction))
           continue;
       CMesh *cm = accumulate(it, mesh.end(), func);
       shape.push_back(cm->CreateShape());
   }
}
 
 
« Последнее редактирование: Март 15, 2011, 23:14 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Март 15, 2011, 23:11 »

Тогда как вариант:
Код
C++ (Qt)
..
       CMesh *cm = accumulate(it, mesh.end(), func);
..
 
Не въехал с сынтаксысом. Вроде "начальное значение" для accumulate обязательно, значит так
Код
C++ (Qt)
       CMesh *cm = accumulate(it, mesh.end(), *it, func);
 
Но тогда последующая проверка на NULL теряет смысл, cm == *it
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #13 : Март 15, 2011, 23:17 »

Цитировать
Не въехал с сынтаксысом. Вроде "начальное значение" для accumulate обязательно,
Да, попутал))

Вот окончательно:
Код
C++ (Qt)
class MyFunctor
{
public:
   CMesh * operator()(CMesh *a, CMesh *b) {
       if ((a->mFriction == b->mFriction) && (a->mFriction == m_unique_friction.back()) && m_tag)
      {
           a->Append(b);
           b->Clear();
       }
        return a;
   }
 
bool frictionIsContains(float f) {
   vector<float>::iterator it = find(m_unique_friction.begin(), m_unique_friction.end(), f);
   if (it == m_unique_friction.end()) {
       m_unique_friction.push_back(f);
       m_tag = true;
       return !m_tag;
   }
    m_tag = false;
    return !m_tag;
}
private:
vector<float> m_unique_friction;
bool m_tag;
};
 
void CMesh::CreateShapes( TMeshPtrVec & mesh, TShapePtrVec & shape )
{
   TMeshPtrVec::iterator it = mesh.begin();
   MyFunctor func;
    for (; it != mesh.end(); ++it) {
       if (func.frictionIsContains((*it)->mFriction))
           continue;
       CMesh *cm = accumulate(it, mesh.end(), *it,  func);
       shape.push_back(cm->CreateShape());
   }
}
 
« Последнее редактирование: Март 16, 2011, 00:30 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #14 : Март 15, 2011, 23:25 »

Это должно быть по быстрее Подмигивающий
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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