• ベストアンサー

動的配列の賢い使い方

動的配列について質問です。 構造体を動的配列で今ボタンを押すたびに値を追加しています。 i = i+1 Redim preserve a(i) as ユーザ定義 ただこの方法だと追加するだけならよいのですが、 削除の時に問題があります。 例えば、配列が5つあるとします。 削除のボタンをクリックし2番目の配列を削除したとします。次に追加ボタンをクリックすると6番目に追加します。 これですと、2番目の値がないのに(5つしかないのに)6つ分のメモリを確保することになると思います。 上手はメモリ確保方法はないでしょうか? 構造体のデータは、 ・index ・文字列 ・数値 をそれぞれ持っており、indexは一応追加するごとに増えていくようになっています。 うまく説明できませんが、よろしくお願い致します。

質問者が選んだベストアンサー

  • ベストアンサー
  • xcrOSgS2wY
  • ベストアンサー率50% (1006/1985)
回答No.1

定番的なのは連想配列を使うことで、VBの場合ですとCollectionオブジェクトの使用でしょうか。 構造体のデータを、「Redim+代入」で配列に格納するかわりにCollectionへの追加(Add)にします。そのとき、キーとしてindexと一対一に対応する文字列(strで単に文字列化するのが簡単)を指定しておきます。 これなら、2個追加すれば2個分の情報だけがCollectionの中に蓄積されることになるので、そのindexが1と10000だったとしても中間の2,3,4,...,9999番目の領域まで確保されることはありません。 難点は、配列と比較してデータにアクセスする速度が劣るのと、VBの場合はいちいちキーを文字列化して与えないといけないのが面倒&さらに速度が遅くなる原因になるというところです。

NetMani-_-i
質問者

お礼

早速のご回答ありがとうございます。 Collectionオブジェクトというのがあるのですね。 一つ質問させてください。 Collectionとは配列と同じようなものと考えてよいのでしょうか? 配列と同じように使えるのでしょうか? サンプルサイト等ご存知でしたら教えていただければ幸いです。 ご回答ありがとうございました。

その他の回答 (1)

  • goma_2000
  • ベストアンサー率48% (62/129)
回答No.2

横から失礼します。 Collectionオブジェクトはデータ形式としては配列というよりはListとしての使い方になりますね。 No.1さんがいわれているように、「配列と比較してデータにアクセスする速度が劣る」というデメリットがありますが、それほど配列サイズが大きくないようでしたら問題ないはずです。 多少、実装する気であれば、Index用の配列と実際の内容がある配列の2種類用意すれば回避できます。 Index用の配列では、上記と同じ問題が起きる可能性がありますが、配列サイズはIndexと共に大きくするのではなく、ある大きさに決めておき、配列サイズより大きな値の場合は余りを用いてIndex番号をあらわせばよいです。その際に、Index番号が重複する可能性がありますが、その場合はある定数をベースにしてIndex番号をずらす処理をすれば回避できます。 これはいわゆるHashテーブルってやつですね。Hashテーブルが80%以上埋まった時には再ハッシュといって、ハッシュテーブルを作り直します。 メモリ確保を気にされているようですが、スピードとメモリはトレードオフの関係にあると思ってください。配列方のデータ形式でメモリ的に辛くないのであればそれが一番早いです(O(1)のアクセス時間なので)。そうでなく、メモリ的にかなり辛いのであればList形式(Collectionオブジェクト)となります。中間的?に、メモリを抑えつつ、アクセスを高速にするためには上記のようなHashテーブルを用いるのが良いと思います。

関連するQ&A

  • 動的配列の初期化

    お世話になっております。 redim preserve AAA(i) とループさせて値をいれます。 その後AAAを宣言した時と同じ状態にしたいのですが どのようにすればいいのでしょうか? redim AAA(0) とやりましてもAAA(0)になんらかの値がはいって しまいますし・・・ なにかわかることがあればご回答よろしくお願いします。

  • 動的配列確保

    JAVA初心者です。 VBでのRedim Preserve、CのreallocみたいなものはJAVAには無いのでしょうか? 要はあらかじめ配列数がわかっていない時に動的配列確保を行いたいのです。 Objectではなく、基本クラスのint、byte等の配列に使いたいと思っております。 ArrayListが近い事が出来そうだったのですが、Objectにしか使用出来ないので、 断念しました。教えてください。

    • ベストアンサー
    • Java
  • VBScripの2次元動的配列

    下記VBScripサンプルで2次元動的配列をつかっているのですが redim preserveでエラになります。 (インデックスが有効範囲にありません) 原因をご伝授ください。 環境 IIS 5.0 Windows XP index.asp <%@ LANGUAGE="VBScript" %> <% 'option explicit %> <!-- #include file="test.asp" --> <% Dim Order() Dim dat() call test(Order,dat) response.write("dat=" & dat(1,2)) %> test.asp <%'Option Explicit%> <% function test(Order_info,dat) Dim i redim dat(0,7) for i=0 to 1 <- iが0の時はOK,iが1になるとエラー redim preserve dat(i,7) dat(i,1)="1" dat(i,2)="2" dat(i,3)="3" dat(i,4)="4" dat(i,5)="5" dat(i,6)="6" next End function

  • AccessVBAで、二次元配列を動的に設定したい

    以下のコードにあるattrという配列に、DB上のとあるコードと名前を設定したいと思います。 DB上のデータ量は可変なので、データを取得するごとに動的に配列attrの要素数を動的に増やしたいと思っています。 検索等で色々と調べながら以下のコードを書いてみたのですが、どうもうまく動きません。 ご教授願います。 --------------------------------------------------- Dim attr() As String [loop start] ReDim Preserve attr(i, 0) ReDim Preserve attr(i, 1) attr(i, 0) = コード attr(i, 1) = 名前 [loop end]

  • VBAでバイナリとして配列の一部を書き込む方法

    配列a(256, 256)をまるごとバイナリデータとして書き込みたい場合には Put #1,,a a(256, 256)の配列に入った数値のうち、 a(51,51)~a(256,256) に入った数値のみをバイナリデータとして書き込みたいのですが どのようにすれば良いですか? で次元を変更して、この配列の中のデータを消さないままで a(0,0)~a(50,0)とa(0,0)~a(0,50) を削除してa(206,206)の配列を作成したいのですが、 ReDim Preserve a(206,206) とすると ”インデックスが有効範囲にありません”というエラーがでます。 http://hpcgi1.nifty.com/kenzo30/b_cbbs/cbbs.cgi?mode=al2&namber=7771&rev=&no=0&P=R&KLOG=51 このページにあるように、 ReDim Preserveは一次元配列でしか使えないそうです。 どうすれば一部だけバイナリに書き込めますでしょうか?

  • VBAでオブジェクトの配列の配列の削除をすると動作異常になります

    VBA(Excel2000)でオブジェクト指向のお勉強をしておりますが、ミスか言語仕様か分からないトラブルがあり、困っております。 簡単な碁(碁盤を再現し、活き死に程度を判定する)のプログラムを作成していますが、クラス石の配列であるクラス群を作成し、更にクラス群の配列を石の黒・白別に標準モジュールで定義しています。一塊の石の群が死んでいると判定した時、その群を削除しようとするのですが、redim preserve 群の配列(添字-一番最後の)を実行すると、群の配列全体にアクセスできなくなってしまいます。redimする前に、Nothingを代入するとか、もとの群(石の配列)にNothingを代入してからredimするとかしてみましたが、事態は変わりませんでした。 仕様なのか、勘違いしているのか、クラスの使い方が分かっていないのか..アドバイスお願いします。

  • ReDim PreserveよりもReDimが遅い

    こんにちは、配列がいくつまで取得できるのか計算するマクロを作っている時に変なことに気が付きました。 エクセルでフォームとラベルを1つ用意し、下記のようなプログラムをモジュールに書きます。 実行すると、10万ずつ数字が増えていき、数字が1000~2000万超えたあたりで、メモリ不足ですという 表示がでます。 ここで、ReDim PreserveのPreserveをとって、ReDimだけにすると、数字の増え方が目に見えて遅くなります。 ReDim Preserveとしたときは9.5秒ぐらいですが ReDim の時は 30秒以上かかっています 3台のマシンでテストしましたが、どれも似たような結果になりました 普通に値を保持するredim Preserveの方が遅いと思うのですがなぜこのような結果になるのでしょうか? ご教授お願いいたします。 Public Sub 配列上限取得計算() On Error GoTo ErrEnd Dim i As Long Const kankaku As Long = 100000 ReDim ans(1 To kankaku) As String ans(1) = 1 i = 2 UserForm1.Show vbModeless Do If i Mod kankaku = 0 Then DoEvents UserForm1.Label1 = i 'ここのPreserveをなくすと明らかに遅くなる ReDim Preserve ans(1 To i + kankaku) As String End If ans(i) = i i = i + 1 Loop Erase ans Unload UserForm1 Exit Sub ErrEnd: MsgBox "これ以上の配列を設定できません。" & vbCrLf & "上限は" & i & "です。" & vbCrLf & Err.Description Erase ans Unload UserForm1 End Sub

  • ASPのReDim Preserveについて

    いつもお世話になります。 ASP(VBScript)で教えて頂きたいことがあります。 VBScriptにはJavaでいうArrayListのようなコレクション機能がないので、動的配列を実現するためには ReDim PreserveやScripting.Dictionaryを使用しなければなりませんよね。 そこで、DBから取得したレコードを、ループする度毎にReDim Preserveを使用し、データをセットするよう な実装をしていました。すると、ReDim Preserveは問題があるのでやめた方がよい、と言われました。 具体的には、ReDim Preserveをすることによって、新たに配列を作成し、古い内容をコピーするため、 倍々にメモリを食いつぶしていくことになり、それが大きくなるとどんどん遅くなっていき、そしてメモリリーク になる、ということでした。 自分なりに調べてみたのですが、そのような記事を見つけることができませんでしたし、JavaのArrayList でも内部的には配列を持っており、配列の再作成などをやっています。 ○○百万件などといった大量件数を扱う際は、それはメモリリークにならないような設計、実装をしなければ ならないとは思うのですが、それはどの言語でも共通で言えることであって、特別にVBScriptではやめた方がよい、 とは思えません。 ReDim Preserveを使用しても、先に述べたような認識をもっていれば問題ないと思うのですが、どうでしょうか。 VBScriptは、こういう仕組みだから駄目なんだ、という理由があるのでしょうか。もしあれば、根拠となる サイトなど教えて頂けると嬉しいのですが。。。 宜しくお願い致します。

  • VBA 配列について

    配列の使い方について教えてください 1つの配列をどんどん追加したりしたいので1つの mybox で追加していきたいと思っています。 (下記コードが実現できればと思います。) (1)配列を広げ追加したい (2)繰返しを使わず一気に書き込みたい (3)一部をクリアしたりしたい のですがよろしくお願いします。 Sub Macro1() Range("A1").Value = "A" Range("A2").Value = "B" Range("A3").Value = "A" o = Range("A1").End(xlDown).Row mybox = Range(Cells(1, 1), Cells(o, 1)).Value 'myBox(1,1)=A 'myBox(2,1)=B 'myBox(3,1)=A ←このような表示になります。 '------------------------------------------------- '(1)配列を広げ追加したい ReDim Preserve mybox(o, 2) For i = 1 To UBound(mybox) If mybox(i, 1) = A Then mybox(i, 2) = 0 Else mybox(i, 2) = 1 End If Next i '------------------------------------------------- '(2)(1)をC列に「myBox(?,2)を「繰返しを使わず一気に」書き込みたい 'Transposeは限界(65536個)を超えるので使えません。 Range(Cells(1, 3), Cells(UBound(mybox), 3)) = mybox '(3)配列myBox(?,1)は残したままmyBox(?,2)はクリアにしたい End Sub

  • アドレス格納のための二次元配列のメモリ動的確保

    アドレス格納のための二次元配列のメモリ動的確保 二次元配列のためにメモリを動的確保しなければならないのですが、 その配列に格納したいものが 「DATA型のポインタ」です。(DATA型はtypedefした構造体です。) プログラム実行中にmallocで確保した、数あるDATA型の構造体の、その先頭アドレスを リストアップするための配列です。 この場合、どのような形でmallocすればよいのでしょうか? 教えていただけるとありがたいです。よろしくお願いいたします。 -- たとえば m×n のint型の配列は、 ◆ int *i; ◆ i = (int *)malloc( m * n * sizeof(int) ); となりますよね。 この要領がでやるのが一般的にわかりやすいものだとするならその方法でやりたい (後発の人が自分のソースコードを読む可能性があるため)のです。 -- 同様にm×nの「DATA型のポインタを格納するための二次元配列」を動的確保したい場合、 ◆ DATA *d; ◆ d = (DATA *)malloc( m * n * sizeof(DATA) ); この文にどのように付け加えたら良いのでしょう? もうあと一歩な気がするのですが(笑)。しかし参考書等で勉強しましたがわかりませんでした・・・。 わかる方、どなたかよろしくお願いいたしますm(_ _)m あとこれだけ通ればコンパイルが通るんです!!!!! たぶん(笑)

専門家に質問してみよう