Szybkie sumowanie.

  Algorytm pokazuje jak w prosty sposób można przeprowadzić sumowanie kolumn liczbowych zawierających nawet kilkadziesiąt milionów wierszy. Zaletą prezentowanego tutaj sposobu jest to, że aktualizowanie kolumn liczbowych nie wymaga przeliczania wszystkich wartości jakie się w nich znajdują.
  Sprawdźmy na przykładzie jak będzie wyglądało sumowanie kolumny zawierającej przykładowe wartości, tak jak to pokazanow w tabeli:

wiersz [1].100,00
wiersz [2].200,00
wiersz [3].300,00
wiersz [4].400,00
wiersz [5].500,00
wiersz [6].600,00


  Algorytm sumowania dla tej tabeli mógłby wyglądać np. tak:


 int suma = 0;

 for(int i = 0; i < 6; i++){

    suma = suma + wiersz[i];

                           }


... i w zasadzie sumować wartości można tylko przez kolejne ich zliczanie, jeśli zliczamy kolumny zawierające kilka, lub nawet kilkaset wierszy to opóźnienie w działaniu kodu będzie niezauważalne. Co jednak jeśli kolumna zawiera milion wierszy? No cóż zliczanie nawet na szybkich komputerach może zająć kilka minut, ale niekoniecznie.
  Zacznijmy więc od utworzenia nowego projektu, zapiszmy go pod dowolną nazwą. Następnie umieśćmy na formularzu dwa komponenty: 'StringGrid' i 'Edit1'. Teraz ustawmy ich właściwości tak jak to podano niżej:

StringGrid1wartość:
ColCount2
OptionsgoEditing = true
OptionsgoAlwaysShowEditor = true
RowCount1000000


Edit1           wartość:
Textpozostaw pole puste           


 
 Następnie przechodzimy do pliku nagłówkowego (np. Unit1.h) i dodajemy wpisy do sekcji 'private':

// Plik nagłówkowy np. Unit1.h.
//--------------------------------
private:

void __fastcall Indeksowanie(int n, int c);
void __fastcall Dodawanie(int n, String t);
AnsiString Wpisz(double s);
double id[1000000];
double suma;
//--------------------------------
plik tekstowy


  Teraz przechodzimy do pliku źródłowego (np.Unit1.cpp) i tworzymy nowe zdarzenia:

// Plik źródłowy np. Unit1.cpp
//--------------------------------
void __fastcall TForm1::Indeksowanie(int n, int c)
{
suma = 0;
for(int i = 0; i < n; i++){
if(!StringGrid1->Cells[c][i].Trim().IsEmpty()){
String a = StringReplace(StringGrid1->Cells[c][i + 1].Trim(), " ", "", TReplaceFlags() << rfReplaceAll);
try{id[i] = a.ToDouble();}catch(...){id[i] = 0;}
}
else{id[i] = 0;}
suma = suma + id[i];
}
Edit1->Text = Wpisz(suma);
}
//--------------------------------
AnsiString TForm1::Wpisz(double s)
{
String a = FloatToStrF(s, ffNumber, 13, 2);
return a;
}
//--------------------------------
void __fastcall TForm1::Dodawanie(int n, String t)
{
String a = StringReplace(t.Trim(), " ", "", TReplaceFlags() << rfReplaceAll);
suma = suma - id[n];
try{id[n] = a.ToDouble();}catch(...){id[n] = 0;}
suma = suma + id[n];
}
//--------------------------------
plik tekstowy


W zdarzeniu formularza 'OnShow' umieszczamy instrukcję:

// Plik źródłowy np. Unit1.cpp
//--------------------------------
void __fastcall TForm1::FormShow(TObject *Sender)
{
Indeksowanie(StringGrid1->RowCount - 1, 1);
}
//--------------------------------


Przechodzimy do komponentu 'StringGrid1' i w zdarzeniu 'OnSelectCell' umieszczamy instrukcję:

// Plik źródłowy np. Unit1.cpp
//--------------------------------
void __fastcall TForm1::StringGrid1SelectCell(TObject *Sender, int ACol,
                    int ARow, bool &CanSelect)
{
Dodawanie(StringGrid1->Row, StringGrid1->Cells[1][StringGrid1->Row]);
Edit1->Text = Wpisz(suma);
}
//--------------------------------



  Teraz w skrócie jak to działa:
Więc po pierwsze w pliku nagłówkowym została zdefiniowana nowa tablica przechowująca wartości liczbowe zmiennopozycyjne - 'double id[1000000]' (wartość 1000000 ogranicza liczbę wierszy, tę wartość można zmienić w zależności od potrzeb) oraz zmienna tego samego typu służąca do przechowywania sumy wszystkich wartości z tablicy - 'double suma'.
W utworzonym zdarzeniu 'void __fastcall Indeksowanie(int n, int c)' wartości liczbowe z kolumny 1 tabeli 'StringGrid1' zostają skopiowane do tablicy 'id' a suma zostaje zapamiętana w zmiennej 'suma' i wpisana do komponentu 'Edit1' za pośrednictwem metody 'AnsiString Wpisz(double s)'. Indeksowanie zostaje przeprowadzone w trakcie uruchamiania programu co będzie powodowało opóźnienie w jego ładowaniu.
  Tablica 'StringGrid' zawiera milion wierszy lecz w chwili ładowania wszystkie są puste dlatego założenie 'if(!StringGrid1->Cells[c][i].Trim().IsEmpty())' służy do pomijania wierszy pustych i przypisywania tablicy 'id[i]' wartości 0.
  Blok 'try...catch...' służy do sprawdzania czy wiersz zawiera liczbę, czy może tekst, jeżeli zawiera tekst to tablicy 'id[i]' przypisywane jest 0. Dokładnie to blok 'try{;}catch(...){;}' działa na zasadzie: "spróbuj przkaształcić tekst zawarty w wierszu obiektu StringGrid na liczbę i wpisz go do tablicy, a jeśli się nie uda to przypisz tablicy wartość 0".
  Zdarzenie 'void __fastcall Dodawanie(int n, String t)' służy do aktualizacji zmiennej 'suma' i tablicy 'id'. Aktualizacja następuje przy każdym przeskoku z jednego do drugiego wiersza tabeli 'StringGrid1'. Aktualizacja tablicy 'id' nie polega jednak na przeliczaniu wszystkich wartości które się w niej znajdują, lecz tylko tych które ulegają zmianie przez co przeliczanie całej tablicy przebiega w "mgnieniu oka" i nie powoduje to przerw w działaniu programu.
  Dużym problemem okaże się jednak wczytanie pliku zawierającego wartości liczbowe oraz przepisanie ich do tablicy 'StringGrid1', ponieważ zajmie to kilkanaście minut no i samo indeksowanie tablicy zajmie również kolejne kilkanaście minut.

Rozmiar: 298 bajtów...pliki źródłowe (BCB 4).