Solved

Array....

Posted on 2001-07-01
18
410 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
  • 8
  • 4
  • 2
  • +2
18 Comments
 
LVL 27

Accepted Solution

by:
kretzschmar earned 100 total points
Comment Utility
why not a tstringlist?
0
 
LVL 27

Expert Comment

by:kretzschmar
Comment Utility
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
Comment Utility
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
 
LVL 27

Expert Comment

by:kretzschmar
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
hmm, a tstringlist would be better than this answer
(just my thought)
0
 
LVL 1

Expert Comment

by:edsteele
Comment Utility
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
Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

 
LVL 5

Expert Comment

by:TheNeil
Comment Utility
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
Comment Utility
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
Comment Utility
no comment,
except that a while-loop is faster than a for-loop
0
 
LVL 5

Expert Comment

by:TheNeil
Comment Utility
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
Comment Utility
? 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
Comment Utility
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
Comment Utility
not at all, theneil, i don't feel so that something had stolen from me :-)
0
 

Author Comment

by:mantra246
Comment Utility
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
Comment Utility
well, thanks :-)

glad to be of service
good luck again

meikl ;-)
0

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

Suggested Solutions

Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
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…
Internet Business Fax to Email Made Easy - With eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, fr…
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…

744 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

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now