1

Тема: Помилка у вибірці даних з StringGrid (IDE С++ Builder)

Доброго дня, шановні! Завчасно вибачаюсь за можливо простеньке запитання та не дуже привабливий код, бо я програміст-початківець.
Власне запитання: мені потрібно вибрати з таблиці StringGrid товар, що купують найчастіше та найрідше за заданий проміжок часу. Власне вибірку код проводить правильно, але іноді не враховує останні рядки. Проте якщо зробити вибірку з уже вибраного товару, то все добре.  Дуже сподіваюся на Вашу підказку або будь-яку іншу допомогу.
Код обробника події клацання по кнопці "Пошук":

\
StringList * T = new TStringList;
  T->Clear();
 //Вибір рядків із вказаного діапазону дат
 //запис даних рідків до списку Т

  for(int i=1;i<TabVZak->RowCount;i++)
   {
     if(StrToDate(TabVZak->Cells[4][i])>DateTimePicker1->Date)
      if(StrToDate(TabVZak->Cells[4][i])<DateTimePicker2->Date)
         T->Add(TabVZak->Rows[i]->DelimitedText);
   }
  //Заповнення таблиці данимим зі списку Т
  TabVZak->RowCount=T->Count+1;
  for(int i=1;i<TabVZak->RowCount;i++)
     TabVZak->Rows[i]->DelimitedText=T->Strings[i-1];

 TStringList * K = new TStringList;
  K->Clear();
  //Вибір строк з однаковою назвою товару
  for(int i=0;i<T->Count;i++)
  {
     for(int j=i+1;j<T->Count;j++)
        if(TabVZak->Cells[1][i+1]==TabVZak->Cells[1][j+1]) //порівняння назв
        {
           //запис до першого рядка з такою назвою, суми кількості проданого товару 
           TabVZak->Cells[2][i+1]=StrToInt(TabVZak->Cells[2][i+1]) + StrToInt(TabVZak->Cells[2][j+1]);
           //запис до першого рядка з такою назвою, суми ціни проданого товару 
           TabVZak->Cells[3][i+1]=FloatToStrF(StrToFloat(TabVZak->Cells[3][i+1]) + StrToFloat(TabVZak->Cells[3][j+1]),ffFixed,8,2);
           //заміна першого рядка на змінені дані
           T->Strings[i]=TabVZak->Rows[i+1]->DelimitedText;
           //видалення повторюваного рядка
           T->Delete(j);

        }

   K->Add(T->Strings[i]);
   }

  TabVZak->RowCount=K->Count+1;
 //Вивід у таблицю отримані дані
  for(int i=1;i<TabVZak->RowCount;i++)
     TabVZak->Rows[i]->DelimitedText=K->Strings[i-1];

 //BubbleSort за зменшенням кількості проданого товару
 AnsiString H;
  for(int i=1;i<TabVZak->RowCount;i++)
      for(int j=1;j<TabVZak->RowCount;j++)
         if(TabVZak->Cells[2][i]>TabVZak->Cells[2][j])
             {
                 H=TabVZak->Rows[i]->DelimitedText;
                 TabVZak->Rows[i]=TabVZak->Rows[j];
                 TabVZak->Rows[j]->DelimitedText=H;
             }

     T->Clear();
Подякували: Replace, koala3

2 Востаннє редагувалося koala (18.11.2013 09:22:28)

Re: Помилка у вибірці даних з StringGrid (IDE С++ Builder)

0. Нарешті нормально сформульоване запитання на форумі! Дякую.
Загальне:
1. Вказуйте, будь ласка, ще використовувані бібліотеки/комплятор/середовище розробки. Засоби C++Builder відмінні від "класичного" MSVS, а ті - від .Net і Qt; а ще в них є різні версії. Навіть C++98, C++03 і С++11 відрізняються.
2. Не треба очищати TStringList-и після створення, вони й так пусті. Це не стандартні типи даних, там конструктори все чистять.
3. Змінні краще створювати перед використанням:

if(TabVZak->Cells[2][i]>TabVZak->Cells[2][j])
{
  AnsiString H=TabVZak->Rows[i]->DelimitedText;
  TabVZak->Rows[i]=TabVZak->Rows[j];
  TabVZak->Rows[j]->DelimitedText=H;
}

Ну і std::swap.
4. Назви змінним все ж краще давати змістовні. T - ну гаразд, тимчасова(?), а що таке K і чим вона відрізняється?
5. Краще на початку функції витягати всі данні з форми, а наприкінці розміщувати назад. Операції з графічними елементами викликають купу додаткових дій, які, наприклад, зовсім не потрібні при сортуванні.
6. Не забувайте видаляти змінні в купі:

delete K;
delete T;

По суті:
7. Ви видаляєте знайдені рядки з T. При цьому змінюються параметри циклу, а ви в ньому неявно виходите з того, що T->Count збігається з TabVZak->RowCount-1. Самі подумайте, як це краще полагодити.
8. Це не бульбашкове сортування. Це погіршене сортування вибором (знаходимо мінімум, записуємо в перший елемент; знаходимо мінімум серед решти, записуємо в другий і т.д.), з купою зайвих обмінів. В бульбашковому обмінюються місцями тільки сусіди. Нічого страшного, я сам таку помилку колись робив... і досі соромно :)

Подякували: Replace, seltsam2

3

Re: Помилка у вибірці даних з StringGrid (IDE С++ Builder)

Дуже дякую за розгорнуту відповідь та моя проблема у тому, що я ніяк не можу "полагодити " цю частину коду. Можливо хтось може мені допомогти? Заздалегіть дякую.

// Вибір строк з однаковою назвою товару
for(int i=0;i<T->Count;i++) {
    for(int j=i+1;j<T->Count;j++)
        if(TabVZak->Cells[1][i+1]==TabVZak->Cells[1][j+1]) //порівняння назв
        {
            //запис до першого рядка з такою назвою, суми кількості проданого товару
            TabVZak->Cells[2][i+1]=StrToInt(TabVZak->Cells[2][i+1]) + StrToInt(TabVZak->Cells[2][j+1]);
            //запис до першого рядка з такою назвою, суми ціни проданого товару
            TabVZak->Cells[3][i+1]=FloatToStrF(StrToFloat(TabVZak->Cells[3][i+1]) + StrToFloat(TabVZak->Cells[3][j+1]),ffFixed,8,2);
            //заміна першого рядка на змінені дані
            T->Strings[i]=TabVZak->Rows[i+1]->DelimitedText;
            //видалення повторюваного рядка
            T->Delete(j);
        }
    K->Add(T->Strings[i]);
}

4

Re: Помилка у вибірці даних з StringGrid (IDE С++ Builder)

Ви забули "хвіст", без якого код не має сенсу:

  TabVZak->RowCount=K->Count+1;
 //Вивід у таблицю отримані дані
  for(int i=1;i<TabVZak->RowCount;i++)
     TabVZak->Rows[i]->DelimitedText=K->Strings[i-1];

А тепер дивіться. У вас є таблиця TabVZak зі значеннями рядків, що повторюються, яка в цьому коді "стискається". Є таблиця (з рядків) T, що є на початку коду копією TabVZak, але "стискається" іншим чином, не так, як TabVZak. І є таблиця з рядків K, що є пустою, а наприкінці стає, знову ж таки, копією стиснутої TabVZak. І нащо таке різноманіття? Якщо вже так кортить із StringGrid-ом працювати (я вже казав, що це погано?), а порядок не має значення (ми ж далі все одно сортуватимемо), то

for(int i=1;i<TabVZak->RowCount-1;i++)
{
  for(int j=i+1;j<T->RowCount;j++)
    if(TabVZak->Cells[1][i+1]==TabVZak->Cells[1][j+1]) //порівняння назв
    {
      //запис до першого рядка з такою назвою, суми кількості проданого товару
      TabVZak->Cells[2][i+1]=StrToInt(TabVZak->Cells[2][i+1]) + StrToInt(TabVZak->Cells[2][j+1]);
      //запис до першого рядка з такою назвою, суми ціни проданого товару
      TabVZak->Cells[3][i+1]=FloatToStrF(StrToFloat(TabVZak->Cells[3][i+1]) + StrToFloat(TabVZak->Cells[3][j+1]),ffFixed,8,2);
      //видалення повторюваного рядка (несподівано)
      TabVZak->Rows[j--]->DelimitedText=TabVZak->Rows[--TabVZak->RowCount]->DelimitedText;
      //j зменшили, бо рядки змістилися, і знову треба перевірити рядок із номером j.
}
Подякували: seltsam1

5

Re: Помилка у вибірці даних з StringGrid (IDE С++ Builder)

Я не дуже розумію даний рядок

 TabVZak->Rows[j--]->DelimitedText=TabVZak->Rows[--TabVZak->RowCount]->DelimitedText;

А С++ Builder 6.0 видає так помилку:  F1001 Internal code generator error

6 Востаннє редагувалося koala (19.11.2013 07:18:01)

Re: Помилка у вибірці даних з StringGrid (IDE С++ Builder)

Який він у вас нервовий... Спробуйте

TabVZak->Rows[j]->DelimitedText=TabVZak->Rows[TabVZak->RowCount-1]->DelimitedText;
TabVZak->RowCount=TabVZak->RowCount-1;
j--;

І якщо ви не знаєте інкрементів, то дарма формами зайнялися, не тим голову заб'єте.
До речі, і правда я помилився(видаляв рядок до копіювання), але таку помилку компілятора не очікував. Ще одне підтвердження, що properties - зло :)

7

Re: Помилка у вибірці даних з StringGrid (IDE С++ Builder)

Тепер він взагалі видаляє усі рядки та ще й зациклюється :(

8

Re: Помилка у вибірці даних з StringGrid (IDE С++ Builder)

Тоді вам доведеться розкрити секрет,  що там в тій таблиці знаходиться. Бо телепатично я побачити не можу. Зокрема, не я не розумію, чому ви починали лічити з 1 і ще заглядаєте в i+1 - там що, дані з 2-го рядка починалися?

9

Re: Помилка у вибірці даних з StringGrid (IDE С++ Builder)

Ось власне потрібна частина проекту.
Дані заповнюються з файлу. Я виправила цикл починається з 0. А i+1 бо у StringList рахунок починається з 0, а у StringGrid з 1 (враховується рядок з назвою колонок).

Post's attachments

pr.rar 370.21 kb, 435 downloads since 2013-11-19 

10 Востаннє редагувалося koala (19.11.2013 14:21:49)

Re: Помилка у вибірці даних з StringGrid (IDE С++ Builder)

А так?

      for(int i=1;i<TabVZak->RowCount;i++)
        for(int j=i+1;j<TabVZak->RowCount;j++)
        if(TabVZak->Cells[1][i]==TabVZak->Cells[1][j])
        {
          TabVZak->Cells[2][i]=StrToInt(TabVZak->Cells[2][i]) + StrToInt(TabVZak->Cells[2][j]);
          TabVZak->Cells[3][i]=FloatToStrF(StrToFloat(TabVZak->Cells[3][i]) + StrToFloat(TabVZak->Cells[3][j]),ffFixed,8,2);
          TabVZak->Rows[j--]->DelimitedText=TabVZak->Rows[TabVZak->RowCount-1]->DelimitedText;
          TabVZak->RowCount=TabVZak->RowCount-1;
         }
Подякували: seltsam1

11 Востаннє редагувалося seltsam (19.11.2013 14:58:56)

Re: Помилка у вибірці даних з StringGrid (IDE С++ Builder)

Працює! Ви навіть не уявляєте як я Вам вдячна!!!
Якщо Вам не важко поясніть будь-ласка цей рядок

 TabVZak->Rows[j--]->DelimitedText=TabVZak->Rows[TabVZak->RowCount-1]->DelimitedText;

12

Re: Помилка у вибірці даних з StringGrid (IDE С++ Builder)

А що саме в ньому незрозумілого?

13

Re: Помилка у вибірці даних з StringGrid (IDE С++ Builder)

мабуть оцей оператор ;) :

--]->

14

Re: Помилка у вибірці даних з StringGrid (IDE С++ Builder)

Це вам квітка :)

15

Re: Помилка у вибірці даних з StringGrid (IDE С++ Builder)

Все зрозуміло. Дуже Вам дякую!

Подякували: koala1

16

Re: Помилка у вибірці даних з StringGrid (IDE С++ Builder)

Очі.завидющі написав:

мабуть оцей оператор ;) :

--]->
Прихований текст

На меч більше схоже =)