user6574802
user6574802

Reputation:

Count how many elements in array

Are there any way to count how many elements there are in an array by using code?

for example:

arrName   : array[1..20] of string;

I already know that there are 6 names stored in that array, but how can I use coding to determine that?

Upvotes: 5

Views: 11774

Answers (3)

Johan
Johan

Reputation: 76567

Yes, but only if the array contains managed types.
Have a look at the following code sample.

procedure TForm1.Button1Click(Sender: TObject);
var
  sa: array[0..19] of string;
  i: Integer;
begin
  for i := 0 to 5 do
    sa[i]:= 'test'+IntToStr(i);
  for i := 6 to High(sa) do begin
    if sa[i] <> '' then ShowMessage('oops');  //will never be triggered.
  end;
end;

Note the empty string aka '' is a valid string. If you allow the program to store empty strings in this array your scheme will fail; if so you'll need to initialize the array with a placeholder string.

Managed types are initialized empty
When you debug this sample and bring up the CPU window, you'll see the following initialization code:

Unit1.pas.30: begin
005C9B24 55               push ebp
005C9B25 8BEC             mov ebp,esp
......
005C9B3F E8F811E4FF       call @InitializeArray
......
Unit1.pas.31: for i := 0 to 5 do

In the begin statement a call is made to InitializeArray because the array contains string.

If the array contains: string, interface , dynamic array, variant or anonymous method (or records containing any of these) then it will be initialized.

Non-managed types are not initialized
If the array contains anything else it will not be initialized; meaning that it will contain whatever was in that piece of memory before.

procedure TForm1.Button1Click(Sender: TObject);
var
  sa: array[0..19] of integer;
  i: Integer;
begin
  for i := 0 to 5 do
    sa[i]:= i+1;
  for i := 6 to High(sa) do begin
    //will most likely be triggered
    if sa[i] <> 0 then ShowMessage('no init for integer');  
  end;
end;

(Obviously a **dynamic** array (an array without pre-set bounds) will be zeroed before use and when expanding)

This does not apply to class members
All members (aka fields) of a class are initialized to zero when an object (instance of that class) is created.
Global variables are also zero initialized. Variables local to a method are not.

Clever programming
If you are somehow forced to use a fixed length array to store a variable number of strings, it is wasteful to count the number of items by traversing the array.
Much better to have a counter in place that keeps track of the number of elements.

type
  TNames = record
    count: integer;
    items: array[0..20] of string;
  end;

Otherwise you'll fall into a Schlemiel the painter trap; a well known antipattern.

Upvotes: 8

Rudy Velthuis
Rudy Velthuis

Reputation: 28806

So you have a fixed size array of 20 elements, but not all of them are valid strings.

One option is to keep track of the number of valid items when you fill the array, in a special variable. This variable starts with 0, and each time you add a string to the array, you increment it. This assumes that all valid items are in a contiguous range from the start of the array (i.e. there are no gaps, and "empty" items are only found at the end). This is how classes like TList keep track of the count of their items.

In this case, because the items are strings, you can simply count the valid strings. Strings are initialized to '', so you can simply test for ''. To make things easier later on, first define a type for the array. Then you can declare a variable of that type and re-use that type in a parameter declaration.

type
  TStringArray = array[1..20] of string;

var
  arrName: TStringArray;

function ItemCount(const A: array of string): Integer;
var
  I: Integer;
begin
  Result := 0;
  for I := Low(A) to High(A) do
    if A[I] <> '' then
      Inc(Result);
end;

Of course this only works if '' is not a valid entry.

Upvotes: 0

John Easley
John Easley

Reputation: 1570

procedure TForm1.Button1Click(Sender: TObject);
var
  i, ArrayCount: integer;
  ArrName : Array[1..20] of string;
begin
  ArrayCount := 0;
  ArrName[1] := 'Bob';
  ArrName[2] := 'Bill';
  for i := low(ArrName) to high(ArrName) do
    if ArrName[i] <> '' then
      inc(ArrayCount);

  showmessage(IntToStr(ArrayCount));
end;

You could also create a function to count your array for you:

function ArrayValueCount(const InputArray: Array of string): integer;
var
  i: integer;
begin
  result := 0;
  for i := low(InputArray) to high(InputArray) do
    if InputArray[i] <> '' then
      inc(result); 
end;

Upvotes: 0

Related Questions