TOPページへ戻る  PCページへ戻る  一覧へ戻る

数値を配列として使いたい - - 動的配列の場合

データを読み込んで計算する場合など、毎回データ数が異なる個数の数値を読み込む ことが多々あります。そんなときは動的配列やリストを使って処理をします。 ここでは動的配列の例を示します。

動的配列では、数値を代入する前にSetLength手続きで 配列の長さを欲しいデータ数以上にします。

SetLength(動的配列,長さ)

SetLength手続きでは、長さは0〜255の数字です。そのため、動的配列は 最大で255のデータしか保持できないように思われますが、次のようにarray of をいれこにすることで255以上のデータを保持できます。

var X_Value : array of array of Integer;

※実は255を越えて要素を持つことようですが、 その限界値は不明です。やってみたら480個程度までは配列になりましたが、その後 の配列に正しいデータが入っていなかった記憶があります。

上記は整数型の動的配列の変数宣言です。この配列では最大 255×255=65025個のデータを配列に持つことができます。次のコードで確かめられる と思います。このコードは、フォーム上にLabel1とButton1が配置された簡単なものです。 Button1を押すと1〜65025までの和をLabel1に表示します。


unit Unit1;
 
interface

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

type
   TForm1 = class(TForm)
     Label1: TLabel;
     Button1: TButton;
     procedure Button1Click(Sender: TObject);
   private
     { Private 宣言 }
   public
     { Public 宣言 }
   end;

var
   Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var Value: array of array of Integer;	// 整数型の動的配列
    i,Answer : Integer;			//  カウンタiと答えAnswer
begin
i := 0;
while i < 65025 do			// この辺は下の説明を参照
    begin
    try					// メモリ不足に備える
    SetLength(Value,(i div 255)+1);		// --- A
    SetLength(Value[(i div 255)],(i mod 255)+1);	// --- B
    Value[(i div 255),(i mod 255)] := i + 1;
    i := i + 1;
    except
      on E:EOutOfMemory do		// メモリ不足が発生した際の処理
        begin
	ShowMessage('メモリ不足です');
	exit;			// Button1Clickを終了
    	end;
      end;
    end;

i := 0;
Answer := 0;
while i < 65025 do
    begin
    Answer := Answer + Value[(i div 255),(i mod 255)];
    i := i + 1;
    end;
Label1.Caption := IntToStr(Answer);	// Label1へ答えを入れる
end;

end.

実行結果(左:ボタンを押す前、右:押した後)

 


簡単な説明

上のコードでは、値を配列に入れる直前※1にSetLength手続きで 配列のメモリを確保しています。今回のコードでは配列の個数が65025と分かっていますが、 実際に読み込むデータ数が分からない場合にはこのように書くことになると思います。

arrayをいれこにした場合、添え字は次のようになります。

Value[ i , j ]

SetLengthはまず i の大きさに関して行い(A行)、i の大きさが決まったら 各Value[ i ]に対してSetLengthを行って(B行)います。SetLengthでは配列の個数を指定しますが、 配列の添え字は0から始まるためSetLengthでは+1しています。

SetLengthは新たにメモリ領域を確保する手続きなので、 メモリ不足の場合はエラー(EOutOfMemory)を引き起こします。それを感知できるようにSetLength をtry 〜 exceptで挟んでいます。try文中でEOutOfMemoryエラーが発生した場合、 on E:EOutOfMemory 〜 end;部が実行されます。このコードでは、ユーザにメモリ不足を 通知(ShowMessage()部)してButton1Click手続きを終了するようになっています。

動的配列Valueの各要素Value[ i , j ]にアクセスするには、 上述のように2つの変数 i , j を使いたくなりますが、i の商と余りを求める算術演算子 div、modを使うと j は不要になります※2。ちなみに、array of array of array of 型の 場合は、次のようになります※3

SetLength部分
SeLength(Value,(i div 65025) + 1);
SetLength(Value[(i div 65025)],((i mod 65025) div 255) +1);
SetLength(Value[(i div 65025),((i mod 65025) div 255)],((i mod 65025) mod 255)+1);

配列の各要素
Value[(i div 65025),((i mod 65025) div 255),((i mod 65025) mod 255)]]

※1 このコードでは、 i が+1されるごとにSetLengthが呼び出される ため、先にデータ数を調べてwhile文の前でSetLegnthしてしまう方が早くなります。

※2 変数を1つ減らすことができますが、足し算、引き算に比べて わり算はかなり計算速度を遅くします。そのため、divやmodを使うより j 、k などを導入 した方が高速になると思われます。もちろん、+1ごとに if (i mod 255) = 0 then とやってしまって はダメですが。。。

※3 足し算を65536以上まで行うと、Integerの最大値 (2147483647、DelphiではMaxIntという定数)を越えてしまい、正しい結果を返しません。

TOPページへ戻る  PCページへ戻る  一覧へ戻る