二次元配列の最初の次元のReDim Preserve

解決


smo  2004-12-25 23:09:11  No: 87578

はじめまして。
動的配列の二次元以上の場合、最後の次元以外の値を保持しながらの
Redimは無効化とMSDNライブラリに記入されています。

ReDim Preserve Matrix(UBound(Matrix, 1) + 1, 10)

は無効とありますが、これをどうしても行いたい場合はどのように
すればよろしいのでしょうか?
無理矢理な方法は考え付きましたが

Dim a() As String
Dim b() As String
Private Sub Form_Load()
ReDim a(0, 1000)
For i = 1 To 100
    add
Next i
End Sub

Sub add()
ReDim b(UBound(a) + 1, UBound(a, 2))
For i = 0 To UBound(a)
    For j = 0 To UBound(a, 2)
        b(i, j) = a(i, j)
    Next j
Next i

ReDim a(UBound(a) + 1, UBound(a, 2))
a = b
End Sub

毎回上コードを用いて繰り返しますと処理速度が格段に遅くなります。
値を保有しながらの二次元配列の最後以外のReDim Preserveで良い方法
等ございませんでしょうか?
どうかよろしくお願いいたします。


ねろ  2004-12-26 00:11:39  No: 87579

どんな方法があるかよりも、何で
  ReDim Preserve Matrix(10, UBound(Matrix, 1) + 1)
ではいけないのか、皆知りたいと思うけど。


じゃんぬねっと  URL  2004-12-26 00:18:13  No: 87580

こんにちは、じゃんぬねっと です。

そういう場合は「多次元配列」では扱いづらいので「多段階配列」にした方がいいかもしれませんね。

VB.NET では普通に使えますが、VB6 でしたら Type 定義になりますね。

Private Type TypeArray
    ArrayItem() As String
End Type

Private tArray() As TypeArray


魔界の仮面弁士  2004-12-26 00:23:43  No: 87581

メモリ配置の都合上、Preserverでは無理でしょう。

Integer等の単純な型なら、RtlMoveMemory API等でコピーする事も
できるでしょうが、String型の配列だとそういった方法も取れないので、
ひとつずつ移す必要があるかと。

もし、「A(i, j)」のような2次元配列に拘らないなら、データを
「A(i)(j)」のようなジャム配列で保持しておくのは如何でしょうか。
これなら、それぞれの要素を個別に拡張できますので。

Private A() As Variant
Private Sub Form_Load()
    ReDim A(3)
    A(0) = Split("AAA BBB CCC")
    A(1) = Split("DDD EEE FFF")
    A(2) = Split("GGG HHH III")
    A(3) = Split("JJJ KKK LLL")

    Debug.Print A(2)(1)

    ReDim Preserve A(4)
    A(4) = Split("aaa bbb ccc")
    Debug.Print A(4)(0)
End Sub


smo  2004-12-26 01:27:12  No: 87582

早速の返答ありがとうございます。
肝心のVBのバージョンを記入してませんでした…環境はVB6.0です。
>じゃんぬねっとさん
はじめまして。作成中のプログラムのは

Dim a() as c

Private Type c
        c_a as String
        c_b as Integer
End Type

この構造になってまして上の内容に

Dim a() as d

Private Type d
        d_a() as c
End Type
Private Type c
        c_a as String
        c_b as Integer
End Type

と置き換えるとエラーが発生します。最初にTypeを当ててる事書かずすみません。

>魔界の仮面弁士さん

ジャム配列では上のようなTypeも可能なのでしょうか?

二次元配列の最初の次元のReDim Preserveが出来ない事を知らずに
On Error Resume Nextでエラーをずっと飛ばしてたのでエラーに気がつかず
何度もソースを見直してやっと知りました…メモリ配置の関係で無理なんですね(^-^;)


ねろ  2004-12-26 02:27:06  No: 87583

答えとは全く関係ないけど。
>On Error Resume Nextでエラーをずっと飛ばしてたのでエラーに気がつかず
On Error Resume Nextを入れる時は、あらかじめエラーの原因を100%想定しておかなければ、
出来たものはプログラムとは無縁のものになりますよ。(^^;


smo  2004-12-26 02:40:28  No: 87584

>ねろさん
今回の失敗で改めて身に染みました。
いつも逃げの形でOn Error Resume Next入れてたので・・・反省(T_T)


魔界の仮面弁士  2004-12-26 09:52:14  No: 87585

> On Error Resume Nextで
デバッグ時には、「エラー発生時に中断」モードを併用すると良いですよ。

> エラーをずっと飛ばしてたので
想定外のエラーに備えて、エラートラップを入れるのは構いませんが、
Err.Number等で判断せず、そのまま「無視」してしまうようなコードは、
『エラーの原因が100%想定できる時』以外は止めた方が良いですね。(^^;

> メモリ配置の関係で無理なんですね(^-^;)
『ReDim A(2, 1)』という配列は、メモリ上では
  A(0, 0)
  A(1, 0)
  A(2, 0)
  A(0, 1)
  A(1, 1)
  A(2, 1)
という順番で並んでいるわけです。で、この配列の最後の次元を拡張して
『ReDim Preserve A(2, 2)』とする場合を考えると、メモリ上では、
  A(0, 2)
  A(1, 2)
  A(2, 2)
という領域を、最後に追加する事で、配列の拡張が完了します。

しかし、前の次元まで変更可能にしてしまうと、途中にデータを挿入したり、
それ以降のデータをずらしたりといった処理が必要になってしまいますね。

最後の次元だけ変更可能なのは、この為です。
(正確な説明では無いですが、イメージ的にはこんな感じになってます)


魔界の仮面弁士  2004-12-26 10:18:57  No: 87586

> ジャム配列では上のようなTypeも可能なのでしょうか?
可能か不可能か、なら「可能」です。

VB6からは、VarType関数の戻り値(VbVarType列挙定数)に、
「vbUserDefinedType」が新設された事からもわかりますように、
Variant型にユーザー定義型を格納する事もできますからね。

ただ、そのための手続きは、少々面倒になりますので、できれば
別の手段を用いた方が良いでしょう。
この場合、ユーザー定義型をクラスにしてしまうのが簡単です。

# クラス(というか、オブジェクト)であれば、複雑な手続きも無く、
# Variant型の変数に格納する事が可能です。

もしくは、元の配列を別の形…たとえば1次元配列で管理しておき、
  Public Function GetItem(ByVal P1 As Integer, ByVal P2 As Integer) As MyType
      Dim P As Integer
      P = (P1とP2から、インデックス値を算出)
      GetItem = mMyType(P)
  End Function
などのような変換関数を使ってアクセスするようにするとか。
# たとえば「GetItem(0,0)」が「mMyType(0)」などを返すようにする。


魔界の仮面弁士  2004-12-26 10:25:11  No: 87587

# 長くなっているので、分割して連続投稿してます。m(_ _)m

> Private Type d
>     d_a() as c
> End Type
> Private Type c
>     c_a as String
>     c_b as Integer
> End Type

これ、宣言順がおかしいですね。
d_a() As Cの宣言時には、まだ Type Cは未定義ですから。

この場合は、「Type D」の宣言を「Type C」の後に配置してください。

> この構造になってまして上の内容に
(中略)
> と置き換えるとエラーが発生します。
そのコードで実装するのであれば、
  ReDim A(2, 1)
とする代わりに、
  ReDim A(2)
  ReDim A(0).d_a(1)
  ReDim A(1).d_a(1)
  ReDim A(2).d_a(1)
のようにReDimする事になりますね。


Say  2004-12-27 10:47:23  No: 87588

>> ジャム配列では上のようなTypeも可能なのでしょうか?
> ジャム配列では上のようなTypeも可能なのでしょうか?
「ジャム配列」ではなく、「ジャグ配列(Jagged Arrays)」です。
検索できなくて困るといけないので念のため。


smo  2004-12-27 19:27:07  No: 87589

返答遅れてしまい申し訳ありませんでした。
>魔界の仮面弁士さん
配列の拡張は最後に領域を追加する事で可能なんですね。
Redimだけだと内容を初期化し再度領域確保するので最後次元以外も
変更可能・・・なのかな。

>もしくは、元の配列を別の形…たとえば1次元配列で管理しておき
一つの膨大な配列にし、その中から抽出すれば拡張等簡単に出来ますね。
この方式で進めて行こうと思います。(管理しやすそうですし)

>この場合は、「Type D」の宣言を「Type C」の後に配置してください。
了解しました。順序が逆でしたね・・気をつけたいと思いますm(__)m

曇りがすべて晴れました。アドバイス本当にありがとうございました。
On Error Resume Nextは・・・今後控えたいと思います。

>Sayさん
>「ジャム配列」ではなく、「ジャグ配列(Jagged Arrays)」です。
なるほどジャグでしたか。助言ありがとうございます。


魔界の仮面弁士  2004-12-28 08:51:54  No: 87590

うわわわわ、ホントだ。言われてはじめて気が付きました。
訂正ありがとうございます。>Sayさん

# えーと。回答した本人はジャグと書いていたつもりでした。
## 以前は、ジャグと書いていたのに、なんで間違えたんだろう…。(泣
## http://madia.world.coocan.jp/vb/vb_bbs2/200312_03120120.html


Say  2004-12-28 21:28:22  No: 87591

もちろん、ただのタイプミスなのはわかってます。(^_^)

ふつうは「善意の無視」するんですが、
「気を悪くするかな」とは思いましたが
今回は一番「肝」になる単語だったので。

>訂正ありがとうございます。>Sayさん
そう言ってもらえると、ホッとします。


※返信する前に利用規約をご確認ください。








  このエントリーをはてなブックマークに追加