?
Solved

Array....

Posted on 2001-07-01
18
Medium Priority
?
415 Views
Last Modified: 2010-08-05
i'm using delphi 2 at the moment and have hit a small problem.

I have an array that holds information such as:

a(0):='listing one'
a(1):='listing two'
.
.
.
a(50):='listing fifty';

when i want to remove a bit of information from the array i set it to equal ''

however, what i want to do is have a routine that will go through the array from the beginning to the end and move the information up if it finds an empty space.

ie: if i made a(0):='' then when i run the routine it would have the array as a(0):='listing two', etc.

also, it needs to be aware that there may be several blanks throughout the array and compact the information as above by moving it up.
0
Comment
Question by:mantra246
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 8
  • 4
  • 2
  • +2
18 Comments
 
LVL 27

Accepted Solution

by:
kretzschmar earned 400 total points
ID: 6242018
why not a tstringlist?
0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 6242038
hum, use missed

meant
why not use a tstringslist, its near like an array,
and you can simple delete an entry,
all entrys behind are mocing a step down automatically

meikl ;-)
0
 

Author Comment

by:mantra246
ID: 6242151
hi meikl.  i was told by a friend that a stringlist was one way to do it but i'm a bit unsure of how to do it.

also, my entire program is designed around the array so i don't know if it will work using a stringlist - or am i wrong?
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 27

Expert Comment

by:kretzschmar
ID: 6242223
well, ok,
to avoid many changes in your code

a sample with a cleanup-method

unit shift_array_u;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Edit1: TEdit;
    Button4: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
  private
    FArray : array[0..50] of String;
    procedure InitArray;
    procedure ClearOne(AIndex : Integer);
    procedure showcontent;
    procedure CleanUpArray;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

// Init the array with some text
procedure TForm1.InitArray;
var i : integer;
begin
  for i := 0 to 50 do
    FArray[i] := 'Text'+IntToStr(i);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  InitArray;
end;

//empty one entry
procedure TForm1.ClearOne(AIndex : Integer);
begin
  if (AIndex > 0) and (AIndex <= 50) then
    FArray[AIndex] := ''
  else
    raise exception.create('Invalid Index');
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  clearOne(strToInt(edit1.text));
end;


//show the content in a memo
procedure TForm1.showcontent;
var I : Integer;
begin
  memo1.lines.clear;
  for i := 0 to 50 do
    memo1.lines.add(FArray[i]);
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  ShowContent;
end;

//shifts the array by moving non_empty enties forward, if there are empty entries
procedure TForm1.CleanUpArray;
var
  i,j : Integer;
  endCleanup : Boolean;
begin
  endCleanUp := False;
  i := 0;
  j := 0;
  while not endCleanup do
  begin
    if FArray[i] = '' then
    begin
      j := i+1;
      while (j <= 50) and (FArray[J] = '') do inc(J);  //search for a not empty entry
      If J <= 50 then
      begin
        FArray[i] := FArray[J];
        FArray[J] := '';
      end;
    end;
    inc(i);
    EndCleanUp := (i > 50) or (j > 50);  //end if all cjecked or no none empty entry found
  end;
end;


procedure TForm1.Button4Click(Sender: TObject);
begin
  CleanUpArray;
end;

end.


meikl ;-)
0
 
LVL 5

Expert Comment

by:TheNeil
ID: 6244055
Just to be awkward, the code you need to use your Array approach would be as simple as this:

FOR iCount := iRemove TO (50 - 1)
DO
  a[iCount] := a[iCount + 1];
a[50] := '';

All you need to do is set iRemove to be the index of the item to remove and it'll work a treat

The Neil =:)
0
 

Expert Comment

by:alshaikh
ID: 6244126
Hi Mantra,


Here is an object (MyDynArray) that I think will solve your problem. This object has three properties:  Item[I],  First and Last.

This is self-sizing, self-cleaning dynamic array. To use it, simply create an instance of it and then simply assign items to the item[I] property.

To put a string value at entry 50, all you need is put a line in your code as:

MyStr.Item[50] := ?This is a test? ;

You do not need to wary about the current size of the array, because it will self adjust.

Do delete an entry, simple put this line in your code:

MyStr.Item[50] := ?? ;

I hope this answers you requirements.



//*************** First File *****************************

unit MyDynArr;
interface
Type
  TMyDynArray = Class(TObject)
  private
    FStrArr : Array of String ;

    Function  GetFirst: Integer ;
    Function  GetLast : Integer ;
    Function  GetItem(I: Integer): String ;
    Procedure SetItem(I: Integer; Value: String) ;
    Procedure DeleteEntry(I: Integer) ;
  public
    { Public declarations }
    Property Last : Integer Read GetLast ;
    Property First: Integer Read GetFirst ;
    Property Item[Index: Integer]: String read GetItem write SetItem ;
  end;

implementation


  Procedure TMyDynArray.DeleteEntry(I: Integer) ;
  Var
   J : Integer ;
  Begin
   If (I >= 0) and (I <= High(FStrArr)) Then
   Begin
    For J := I To High(FStrArr)-1 Do
     FStrArr[J] := FStrArr[J+1] ;
    SetLength(FStrArr,High(FStrArr)-1) ;
   End ;
  End ;

  Procedure TMyDynArray.SetItem(I: Integer; Value: String) ;
  Begin
   If Value = '' Then DeleteEntry(I)
   Else Begin
    If I > High(FStrArr) Then SetLength(FStrArr,I+1) ;
    FStrArr[I] := Value ;
   End ;
  End ;

  Function TMyDynArray.GetFirst: Integer ;
  Begin
   Result := Low(FStrArr) ;
  End ;

  Function TMyDynArray.GetLast: Integer ;
  Begin
   Result := High(FStrArr) ;
  End ;

  Function TMyDynArray.GetItem(I: Integer): String ;
  Begin
   Result := FStrArr[I] ;
  End ;

end.

//****************  Second File *****************

unit FrmMainU;
interface
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls,MyDynArr;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    MyStr : TMyDynArray ;
  public
    { Public declarations }

  end;
var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
Var
 A : Array of String ;
 I : Integer ;

 Procedure ShowArray ;
 Var
  I : Integer ;
  S : String ;
 Begin
  S := '' ;
  For I := MyStr.First To MyStr.Last Do
   S := S+MyStr.Item[I]+#13 ;
   ShowMessage(S) ;
 End ;

begin
 MyStr := TMyDynArray.Create ;
 For I := 0 to 6 Do
 MyStr.Item[I] := 'String '+IntToStr(I) ;
 ShowArray ;
 MyStr.Item[3] := '' ;
 ShowArray ;
End ;

end.

//*********** Third File **********************

program TstMyDynArr;

uses
  Forms,
  FrmMainU in 'FrmMainU.pas' {Form1},
  MyDynArr in 'MyDynArr.pas';

{$R *.RES}

begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

0
 

Expert Comment

by:alshaikh
ID: 6244140
Hi Mantra,


In the privus posting, please change "?" to "'".  It should read:

------
To put a string value at entry 50, all you need is put a line in your code as:

MyStr.Item[50] := 'This is a test' ;
-----

-----
Do delete an entry, simple put this line in your code:

MyStr.Item[50] := '' ;
-----

0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 6247393
hmm, a tstringlist would be better than this answer
(just my thought)
0
 
LVL 1

Expert Comment

by:edsteele
ID: 6248738
The Neil has the right idea, but the code given will not quite do the trick.  If there are multiple blank lines in a row, it will miss every other one.  Here is what you want:

procedure TForm1.CompressArray(A: Array of String);
var
  ShouldStop: Boolean;
  Idx, i: Integer;
begin
  ShouldStop := False;
  Idx := Low(A);

  while not ShouldStop do
  begin
    ShouldStop := True;
    if A[Idx] = '' then
    begin
      for i := Idx to High(A) - 1 do
      begin
        A[i] := A[i+1];
        if A[i] <> '' then
          ShouldStop := False;
      end;
      A[High(A)] := '';
    end
    else
    begin
      ShouldStop := Idx = High(A);
    end;
    if A[Idx] <> '' then
      Inc(Idx);
  end;
end;

This has the added benefit that the length of the array doesn't matter. :)

Enjoy!
Eric
0
 
LVL 5

Expert Comment

by:TheNeil
ID: 6249857
Eric's right. A better solution to my FOR approach is a trusty WHILE

iCount := 0;
WHILE iCount < 50
DO
  IF a[iCount] = ''
  THEN
  BEGIN
    a[iCount] := a[iCount + 1];
    a[50] := '';
  END
  ELSE
    iCount := iCount + 1;

The Neil =:)

 
0
 
LVL 1

Expert Comment

by:edsteele
ID: 6249905
The Neil is getting closer, but this one doesn't quite take care of it either.  Not only will it not get all the blanks out, you have the potential for an infinite loop.  If a[3] and a[4] are both blank, when your iCount reaches 3, the while loop is stuck because you move 4 to 3 then clear 50, on the next iteration, the same thing happens again.

On each pass where you find a blank, you need to move all the elements down a notch.  That's the purpose of the for loop in my code.  Also without a special exception, when you run out of non-blank lines the while loop will not exit anyway.  That's why I have the ShouldStop flag in mine.  I assume the loop I am currently in is the last one until I determine that this assumption is false and reset the flag.  If I am able to pass through the loop without hitting a case that flips the flag back to false, all the non-blank lines have been pushed to the bottom. (Or top, depending on how you view it) :)

Eric
0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 6251433
no comment,
except that a while-loop is faster than a for-loop
0
 
LVL 5

Expert Comment

by:TheNeil
ID: 6251687
Cracked it good and proper this time (even if I did have to steal kretzschmar's TStringList idea)

VAR
  stlTemp : TStringList;
  iCount  : LONGINT;
begin
  stlTemp := TStringList.Create;
  TRY
    FOR iCount := 0 TO 50
    DO
      IF a[iCount] <> ''
      THEN
        stlTemp.Add(a[iCount]);
    FOR iCount := 0 TO 50
    DO
      IF iCount > (stlTemp.Count - 1)
      THEN
        a[iCount] := ''
      ELSE
        a[iCount] := stlTemp[iCount];
  FINALLY
    stlTemp.Free;
  END;
end;

The Neil =:)
0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 6251722
? a stringlist would make all easier, because instead to set an entry to '' you can easily delete it -> all above comes automatically one step down by index

only on the filling must be check like

function addstring(AIndex : Integer; AEntry : String) : Integer;
begin
  If AEntry <> '' then
    result := AIndex;
    If AIndex > StringList.Count-1 then
      result := StringList.Add(AEntry)
    else
      StringList[AIndex] := AEntry
  else
    raise exception.create('Attempting to add an invalid entry');
end;

the result holds the index, where the entry is really placed, even this would also dynamic

meikl ;-)
0
 
LVL 5

Expert Comment

by:TheNeil
ID: 6251883
Meikl,

You and I both know that using a TStringlist for storing the data is far better than using an array (more memory efficient, more poerful, no need to re-invent routines etc.). However there might be a good reason for using an array - all depends on what Mantra is trying to do with it

The Neil =;)

PS Sorry for stealing your TStringlist idea (but I did only borrow it a little bit)
0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 6251958
not at all, theneil, i don't feel so that something had stolen from me :-)
0
 

Author Comment

by:mantra246
ID: 6254216
Thanks all but i took the code Meikl gave and the idea of the stringlist and re-worked my code to include it.  it works well and i have tried to "break" it for the past few days and didn't do it so i assume it will hold.
0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 6254828
well, thanks :-)

glad to be of service
good luck again

meikl ;-)
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Monitoring a network: how to monitor network services and why? Michael Kulchisky, MCSE, MCSA, MCP, VTSP, VSP, CCSP outlines the philosophy behind service monitoring and why a handshake validation is critical in network monitoring. Software utilized …
Visualize your data even better in Access queries. Given a date and a value, this lesson shows how to compare that value with the previous value, calculate the difference, and display a circle if the value is the same, an up triangle if it increased…
Suggested Courses

771 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question