String Matrix.

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

String Matrix.

Postby smays » Thu Jul 29, 2010 7:55 am

This may turn out to be a fundamental C++ question. Does the VCL include any m X n string (UnicodeString, AnsiString, whichever) array with the flexibility of TStringGrid, without the visual properties of the TStringGrid? If not, can anyone point me in the right direction to create my own?

Thanks,
Steve.
smays
BCBJ Guru
BCBJ Guru
 
Posts: 165
Joined: Tue Sep 18, 2007 11:28 pm
Location: Huntsville, AL

Re: String Matrix.

Postby gambit47 » Thu Jul 29, 2010 4:24 pm

smays wrote:Does the VCL include any m X n string (UnicodeString, AnsiString, whichever) array


Just declare your own multi-dimensional array, ie:

Code: Select all
UnicodeString array[m][n];


smays wrote:with the flexibility of TStringGrid, without the visual properties of the TStringGrid?


What flexibility are you looking for exactly? I suspect you want to dynamically size the array dimensions at runtime, it that right? If so, then use a std::vector for that, ie:

Code: Select all
std::vector< std::vector<UnicodeString> > array(m);
for(int i = 0; i < m; ++i) array[i].resize(n);
Remy Lebeau (TeamB)
http://www.lebeausoftware.org
User avatar
gambit47
BCBJ Author
BCBJ Author
 
Posts: 472
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: String Matrix.

Postby 2ffat » Fri Jul 30, 2010 6:01 am

I was also going to suggest vectors, maps, deques, and their ilk. Not VCL but standard and a lot of work has been done with them.
James P. Cottingham
There's no place like 127.0.0.1
There's no place like 127.0.0.1
User avatar
2ffat
Forum Mod
Forum Mod
 
Posts: 260
Joined: Wed Jun 23, 2004 7:07 am
Location: South Hill, VA

Re: String Matrix.

Postby smays » Fri Jul 30, 2010 10:45 am

Thanks, guys. This is specifically for what I am looking and, yes, dynamically resizing is what I want. I come across more and more 'dirty' CSV files (CSV files with dumb things like quotations and other undesirable things) and I need to pull them into memory. I typically express them in a TStringGrid, but as I attempt to integrate more and more data from more and more sources - often from a CSV file, I need to stop 'crushing' the screen with grids everywhere.

Anyway, do either of you think it would be safe to 'embed' these dynamically allocated string matrices in my own class? I would like to add basic functionality such as IndexOf(), etc...

What, if anything, do I need to do to clean up this dynamically allocated matrix? Especially if I embed it in a class.

Another question, is it possible to pass a pointer to this vector to a function. For example, say I want to show this data in a grid, but I do not want eat up screen space with another grid, so I pop open a form with a TStringGrid. Is it possible to pass a pointer to the new form and let the new form copy the data to the grid or whatever I have it do?

Thanks!
Steve.
smays
BCBJ Guru
BCBJ Guru
 
Posts: 165
Joined: Tue Sep 18, 2007 11:28 pm
Location: Huntsville, AL

Re: String Matrix.

Postby gambit47 » Fri Jul 30, 2010 5:16 pm

smays wrote:Anyway, do either of you think it would be safe to 'embed' these dynamically allocated string matrices in my own class? I would like to add basic functionality such as IndexOf(), etc...


Of course it would be safe.

smays wrote:What, if anything, do I need to do to clean up this dynamically allocated matrix? Especially if I embed it in a class.


Nothing at all (unless you are dynamically allocating extra memory yourself). The beauty of STL containers is that they manage their own memory for you.

smays wrote:Another question, is it possible to pass a pointer to this vector to a function.


Of course. std::vector is a class like any other (just a templated class), and instances of it operate like normal objects like any other.

smays wrote:For example, say I want to show this data in a grid, but I do not want eat up screen space with another grid, so I pop open a form with a TStringGrid. Is it possible to pass a pointer to the new form and let the new form copy the data to the grid or whatever I have it do?


Sure. On the other hand, I would suggest switching to a TListView in report mode, or to a TVirtualTreeView. That way, you can utilize their virtual modes so you do not have to copy the data into the grid at all, thus reducing your memory overhead while also speeding up the grid in general.
Remy Lebeau (TeamB)
http://www.lebeausoftware.org
User avatar
gambit47
BCBJ Author
BCBJ Author
 
Posts: 472
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: String Matrix.

Postby smays » Mon Aug 02, 2010 11:50 am

Okay, this is what I have so far and I can basically get what I want out of the vector.

Header File:
Code: Select all
class TStringMatrix
{
private:
   std::vector< std::vector<UnicodeString> > vvusStringMatrix;
public:
   __fastcall TStringMatrix(int iNumRows, int iNumColumns);
   __fastcall TStringMatrix(void);
   __fastcall ~TStringMatrix(void);
   UnicodeString __fastcall GetText(int iWhichRow, int iWhichColumn);
};

class TForm1 : public TForm
{
__published:   // IDE-managed Components
   TEdit *Edit1;
   TButton *Button3;
   void __fastcall Button3Click(TObject *Sender);
private:   // User declarations
   TStringMatrix *smStringMatrix;
   void __fastcall AlsoDisplayText(std::vector< std::vector<UnicodeString> > vusStringMatrix, int iThisRow, int iThisColumn);
public:      // User declarations
   __fastcall TForm1(TComponent* Owner);
};


Code File:
Code: Select all
__fastcall TStringMatrix::TStringMatrix(void)
{
   vvusStringMatrix.resize(4);
   for(int iWhichRow = 0; iWhichRow < 4; ++iWhichRow)
      vvusStringMatrix[iWhichRow].resize(3);
   vvusStringMatrix[0][0] = "Row 0, Column 0";
   vvusStringMatrix[0][1] = "Row 0, Column 1";
   vvusStringMatrix[0][2] = "Row 0, Column 2";
   vvusStringMatrix[0][3] = "Row 0, Column 3";
   vvusStringMatrix[1][0] = "Row 1, Column 0";
   vvusStringMatrix[1][1] = "Row 1, Column 1";
   vvusStringMatrix[1][2] = "Row 1, Column 2";
   vvusStringMatrix[1][3] = "Row 1, Column 3";
   vvusStringMatrix[2][0] = "Row 2, Column 0";
   vvusStringMatrix[2][1] = "Row 2, Column 1";
   vvusStringMatrix[2][2] = "Row 2, Column 2";
   vvusStringMatrix[2][3] = "Row 2, Column 3";
}
__fastcall TStringMatrix::TStringMatrix(int iNumRows, int iNumColumns)
{
   vvusStringMatrix.resize(iNumRows);
   for(int iWhichRow = 0; iWhichRow < iNumRows; ++iWhichRow)
      vvusStringMatrix[iWhichRow].resize(iNumColumns);
   for (int iThisRow = 0; iThisRow < iNumRows; iThisRow++)
      for (int iThisColumn = 0; iThisColumn < iNumColumns; iThisColumn++)
         vvusStringMatrix[iThisRow][iThisColumn] = "Row " + IntToStr(iThisRow) + ", Column " + IntToStr(iThisColumn);
}
__fastcall TStringMatrix::~TStringMatrix(void)
{
   vvusStringMatrix.clear();
}
UnicodeString __fastcall TStringMatrix::GetText(int iWhichRow, int iWhichColumn)
{
   UnicodeString usText;

   if (vvusStringMatrix.size() > iWhichRow)
      if (vvusStringMatrix[iWhichRow].size() > iWhichColumn)
         usText = vvusStringMatrix[iWhichRow][iWhichColumn];
      else
         usText = "There aren't as many as " + IntToStr(iWhichColumn + 1) + " columns of data.";
   else
      usText = "There aren't as many as " + IntToStr(iWhichRow + 1) + " rows of data.";

   return usText;
}

void __fastcall TForm1::Button3Click(TObject *Sender)
{
   smStringMatrix = new TStringMatrix(5, 6);

   Edit1->Text = smStringMatrix->GetText(5, 5);
   delete smStringMatrix;
}


Did I do anything especially stupid? Notice in the TStringMatrix destructor I clear() the vector. Is this necessary? Should I put the 'clear()s' in a loop to clear() each of the columns before clear()ing the rows?

Thanks,
Steve.
smays
BCBJ Guru
BCBJ Guru
 
Posts: 165
Joined: Tue Sep 18, 2007 11:28 pm
Location: Huntsville, AL

Re: String Matrix.

Postby gambit47 » Mon Aug 02, 2010 1:54 pm

smays wrote:Okay, this is what I have so far and I can basically get what I want out of the vector.


I would suggest the following changes:

Code: Select all
class TStringMatrix
{
private:
   std::vector< std::vector<UnicodeString> > vvusStringMatrix;
   void Initialize(int iNumRows, int iNumColumns);

public:
   __fastcall TStringMatrix(int iNumRows, int iNumColumns);
   __fastcall TStringMatrix(void);
   UnicodeString __fastcall GetText(int iWhichRow, int iWhichColumn);
};


Code: Select all
__fastcall TStringMatrix::TStringMatrix(void)
{
   Initialize(4, 3);
}

__fastcall TStringMatrix::TStringMatrix(int iNumRows, int iNumColumns)
{
   Initialize(iNumRows, iNumColumns);
}

void TStringMatrix::Initialize(int iNumRows, int iNumColumns)
{
   vvusStringMatrix.resize(iNumRows);
   for(int iWhichRow = 0; iWhichRow < iNumRows; ++iWhichRow)
   {
      std::vector<UnicodeString> &vecRow = vvusStringMatrix[iThisRow];
      vecRow.resize(iNumColumns);
      for (int iThisColumn = 0; iThisColumn < iNumColumns; ++iThisColumn)
         vecRow[iThisColumn].sprintf(L"Row %d, Column %d", iThisRow, iThisColumn);
   }
}

UnicodeString __fastcall TStringMatrix::GetText(int iWhichRow, int iWhichColumn)
{
   if (vvusStringMatrix.size() <= iWhichRow)
      throw Exception("There aren't as many as %d rows of data.", ARRAYOFCONST(( iWhichRow + 1 )) );

   std::vector<UnicodeString> &vecRow = vvusStringMatrix[iWhichRow];

   if (vecRow.size() <= iWhichColumn)
      throw Exception("There aren't as many as %d columns of data.", ARRAYOFCONST(( iWhichColumn + 1 )) );

   return vecRow[iWhichColumn];
}


Code: Select all
class TForm1 : public TForm
{
__published:   // IDE-managed Components
   TEdit *Edit1;
   TButton *Button3;
   void __fastcall Button3Click(TObject *Sender);
private:   // User declarations
   void __fastcall AlsoDisplayText(const TStringMatrix* vusStringMatrix, int iThisRow, int iThisColumn);
public:      // User declarations
   __fastcall TForm1(TComponent* Owner);
};


Code: Select all
void __fastcall TForm1::Button3Click(TObject *Sender)
{
   TStringMatrix smStringMatrix(5, 6);
   AlsoDisplayText(&smStringMatrix, 5, 5);
}

void __fastcall AlsoDisplayText(const TStringMatrix* vusStringMatrix, int iThisRow, int iThisColumn)
{
   Edit1->Text = vusStringMatrix->GetText(iThisRow, iThisColumn);
}
Remy Lebeau (TeamB)
http://www.lebeausoftware.org
User avatar
gambit47
BCBJ Author
BCBJ Author
 
Posts: 472
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: String Matrix.

Postby smays » Mon Aug 02, 2010 3:15 pm

Okay, I noticed you removed the TStringMatrix destructor. Check!

I also noticed the main form (Form1) of your suggested code no longer owns a TStringMatrix(?). Is that correct? So, when the Button3Click() event is completed, smStringMatrix no longer exists and the data is cleared from memory?

Thanks,
Steve.
smays
BCBJ Guru
BCBJ Guru
 
Posts: 165
Joined: Tue Sep 18, 2007 11:28 pm
Location: Huntsville, AL

Re: String Matrix.

Postby gambit47 » Mon Aug 02, 2010 6:34 pm

smays wrote:I also noticed the main form (Form1) of your suggested code no longer owns a TStringMatrix(?). Is that correct? So, when the Button3Click() event is completed, smStringMatrix no longer exists and the data is cleared from memory?


The way you were originally using it (and the way I showed it in my updated example), yes. It was being created and destroyed inside the Button3Click() method only, so there was no point in it being a member of the TForm1 class. But you can certainly do that if you want, ie:

Code: Select all
class TForm1 : public TForm
{
__published:   // IDE-managed Components
   TEdit *Edit1;
   TButton *Button3;
   void __fastcall Button3Click(TObject *Sender);
private:   // User declarations
   TStringMatrix *smStringMatrix;
   void __fastcall AlsoDisplayText(int iThisRow, int iThisColumn);
public:      // User declarations
   __fastcall TForm1(TComponent* Owner);
   __fastcall ~TForm1();
};


Code: Select all
__fastcall TForm1::TForm1(TComponent* Owner)
   : TForm(Owner)
{
   smStringMatrix = new TStringMatrix(5, 6);
}

__fastcall TForm1::~TForm1()
{
   delete smStringMatrix;
}

void __fastcall TForm1::Button3Click(TObject *Sender)
{
   AlsoDisplayText(5, 5);
}

void __fastcall TForm1::AlsoDisplayText(int iThisRow, int iThisColumn)
{
   Edit1->Text = smStringMatrix->GetText(iThisRow, iThisColumn);
}


Or:

Code: Select all
class TForm1 : public TForm
{
__published:   // IDE-managed Components
   TEdit *Edit1;
   TButton *Button3;
   void __fastcall Button3Click(TObject *Sender);
private:   // User declarations
   TStringMatrix smStringMatrix;
   void __fastcall AlsoDisplayText(int iThisRow, int iThisColumn);
public:      // User declarations
   __fastcall TForm1(TComponent* Owner);
};


Code: Select all
__fastcall TForm1::TForm1(TComponent* Owner)
   : TForm(Owner), smStringMatrix(5, 6)
{
}

void __fastcall TForm1::Button3Click(TObject *Sender)
{
   AlsoDisplayText(5, 5);
}

void __fastcall TForm1::AlsoDisplayText(int iThisRow, int iThisColumn)
{
   Edit1->Text = smStringMatrix.GetText(iThisRow, iThisColumn);
}
Remy Lebeau (TeamB)
http://www.lebeausoftware.org
User avatar
gambit47
BCBJ Author
BCBJ Author
 
Posts: 472
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA


Return to Technical

Who is online

Users browsing this forum: Google [Bot] and 1 guest