こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

-広告-

締切り済みの質問

VBA 二次元配列の取り出しと削除

二次元配列 data(200,300)ぐらいの容量のものを20個ぐらい作って使おうと思っています。
data(r,c)のように変数でループさせる予定です。

ここで、二次元配列の使い方についてわからない点が2つあります。

1、容量削減のために、2列前以前の格納されたデータを逐一削除する方法
2、一列のみ取り出すときに記述するコード
についてです。

1、にいては、全体コードのループの最後に下記のように書いているのですが、これで容量削減できているでしょうか?
For r = 0 To 199
data(r, c - 2) = ""
Next r

2、については、一部の列をシートに転記したいのですが、記述法がわかりません。
  例えば、配列内の3列目全てをA列に貼り付けたい場合下記のように書いてもうまくいきません。
.Range("A1:A199") = data( , 2)
  どのように書けばよいか、アドバイスお願いいたします。

投稿日時 - 2015-11-23 11:37:18

QNo.9084785

困ってます

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

-広告-
-広告-

回答(2)

ANo.2

 御質問文に書かれている情報だけでは、最初の

>二次元配列 data(200,300)ぐらいの容量のものを20個ぐらい作って

の際に、どの様にして1200000 件のデータを格納するのか良く解りませんが、回答No.1様も仰っておられる様に、メモリサイズは固定ですので、

For r = 0 To 199
data(r, c - 2) = ""
Next r

などとしても容量削減にはならない筈です。
 容量削減の観点から考えますと、どうせ

data(r, c - 2) = ""

の所で

>2列前以前の格納されたデータを逐一削除

してしまうのですから、格納するデータを「現在の列のデータ」から「2列前のデータ」までの3列のみとし、データの格納先も二次元配列変数の代わりに、どこかの使用していない200行×3列のセル範囲にデータを格納する様にし、

For r = 0 To 199
data(r, c - 2) = ""
Next r

の代わりに例えば

With Application
.ScreenUpdating = False
.Calculation = xlManual
End With
With .Range("Z1:Z199")
Parent.Range("A1:A199").Value = .Value
.Value = .Offset(, -1).Value
End With
With Application
.ScreenUpdating = True
.Calculation = xlCalculationAutomatic
End With

などの様にして、配列変数の2列前に相当するデータを .Range("Y1:Y199")に、1列前に相当するデータを.Range("Z1:Z199")に、3列目に相当するデータを直接.Range("A1:A199")に格納しながら、古いデータを次々と上書きする事で消して行けば良いのではないでしょうか?
(一番最初の1列目のデータをどの様にして格納するのかは知りませんが)
 勿論最後には、

.Range("Y1:Z199").ClearContents

とする事で、無用のデータは消去しておく必要があります。

投稿日時 - 2015-12-01 05:52:53

ANo.1

こんにちは。

> 二次元配列 data(200,300)ぐらいの容量のものを20個ぐらい作って使おうと思っています。
もし、1200000 件のデータを一度に扱う、ということでしたら、
配列変数が目的に適したツールなのか、多少の疑念は残りますし、
責任を持って他人に薦められるものではないです。
量だけで考えるならADOとかでRecordSetとして扱う方が普通で、易しく軽いようにも思いますし、
メモリ上ですべて処理するよりも、一旦ファイルとしてHDDに吐き出してから扱う方が、
負荷が軽く済む場合もある‐量だと思います。
200*300程度に分けて処理するものなのだとして、以下。

> data(r,c)のように変数でループさせる予定です。
であれば、「一部の列をシートに転記したい」
という点についても、直接的にはループで出力すれば可能なのですから
「記述法がわかりません。」というのは少しおかしな感じがします。
どうしたいのか、目的、理由、意図、或いは嗜好等を示した方が
質問として答え易いものになるのではと思います。
配列変数をまるごとセルに一括出力させることで、
処理に要する時間を短く済ませたい、ということなのだとして、以下。

> 1、にいては、全体コードのループの最後に下記のように書いているのですが、これで容量削減できているでしょうか?
> For r = 0 To 199
> data(r, c - 2) = ""
> Next r
「容量」と呼ぶのが、配列の各要素のメモリサイズのことを指しているのであれば、
  配列変数data() が As String で宣言されている(?)のなら、
  data(r, c - 2)はご提示の記述でも初期化されます。
  配列変数data() がVariant型(?)なら、
  data(r, c - 2) = Empty
  配列変数data() が論理型・数値型・通貨型・日付型やユーザー定義型(?)なら、
  メモリサイズは固定ですので、data(r, c - 2) = 0 などとしても手間が増えるだけです。
以下、Excel ヘルプ 開発者用リファレンス - 『データ型の概要』より引用
|メモ どのデータ型の配列にも、20 バイトのメモリ、各配列の次元ごとに 4 バイト、およびデータそのものが占めるバイト数を合計したメモリが必要です。データが占めるメモリのバイト数は、要素数に各要素のサイズを掛けて計算することができます。たとえば、それぞれ 2 バイトの 4 つの整数型の要素からなる 1 次元配列のデータは、8 バイトを占めます。データに必要な 8 バイトとオーバーヘッドの 24 バイトの和により、この配列の合計メモリ必要量は 32 バイトになります。
|   64 ビット プラットフォームでは、SAFEARRAY は 24 ビット (Dim ステートメントごとにさらに 4 バイト) を要します。pvData メンバーは 8 バイトのポインターであり、8 バイト境界に整列する必要があります。
引用、以上。
配列変数(変数)として宣言している以上は初期化してもゼロバイトになることはない、という意味です。

配列の「容量」というと、要素数を指すことが多いのですが、
要素数を変更するのは、
丸ごと宣言し直す
  ReDim vMatrix(1 To 200, 1 To 300)
とか、
要素に格納された値を維持して【最後に宣言するディメンションだけ】をリサイズする
  ReDim Preserve vMatrix(1 To 200, 1 To 299)
とか、Dim vMatrix() の状態に戻す
  Erase vMatrix()
とか、
残念ながら、VBAにはこれ位しか用意されていません。

配列の一部を消したい、という意図だとすると、それは、
配列変数を【直接】処理する方法は、残念ながらVBAには在りません。

場合によっては、提案できる手法も幾つか思い浮かびますが、
何をしたいのか、を理解できないと提示するのは難しいです。
漫然と「配列ありき」の質問をするのが流行っているようですが、
どのような手法を用いるべきか、という点で、
データソースの在り方、中間処理の内容、出力先のサイズと出力方法
の3点を確認できないと、役に立つ回答は出来そうもありません。

お話の概要から推察すると、
Collection オブジェクト や Scripting.Dictionary オブジェクト、を生成するか、
ジャグ配列(多段配列)、を構築するなどして、
【配列の中身が配列、という状況を作って】
上位の配列の要素を.RemoveしたりEraseしたり、
というのが、近い話ではありますが、
それが実際に、質問者さんが抱えた問題の解決に役に立つか、というと、
そうも思えないのです。

> 2、については、一部の列をシートに転記したいのですが、記述法がわかりません。
>   例えば、配列内の3列目全てをA列に貼り付けたい場合下記のように書いてもうまくいきません。
> .Range("A1:A199") = data( , 2)
>   どのように書けばよいか、アドバイスお願いいたします。

Variant型の配列変数をExcel VBAで扱う、という場合に限って言えば、
WorksheetFunctionクラスのIndexメソッドを使う方法(★)があります。
' ' ///
Sub ReW9084785a()
Dim vMatrix()
Dim i As Long, j As Long
' ' 配列変数を初期化
ReDim vMatrix(1 To 200, 1 To 300)
Debug.Print "#1 vMatrix(" & LBound(vMatrix()) & " To " & UBound(vMatrix()) & "," & LBound(vMatrix(), 2) & " To " & UBound(vMatrix(), 2) & ")"
For i = 1 To 200
  For j = 1 To 300
    vMatrix(i, j) = i * 1000 + j
  Next j
Next i
' ' 以上、ダミーデータ、

' ' 二次元配列変数から3列めを切り抜いて出力する例★
Range("A2").Resize(UBound(vMatrix())) = WorksheetFunction.Index(vMatrix(), 0, 3)

' ' 二次元配列変数から5行めを切り抜いて出力する例
Range("B1").Resize(, UBound(vMatrix(), 2)) = WorksheetFunction.Index(vMatrix(), 5, 0)

' ' 右端2列を除いた二次元配列変数をすべて一括出力・例1
Range("B2").Resize(UBound(vMatrix()), UBound(vMatrix(), 2) - 2) = vMatrix()

' ' 右端2列を除いた二次元配列変数をすべて一括出力・例2
ReDim Preserve vMatrix(1 To 200, 1 To 298)
Range("B203").Resize(UBound(vMatrix()), UBound(vMatrix(), 2)) = vMatrix()
Debug.Print "#2 vMatrix(" & LBound(vMatrix()) & " To " & UBound(vMatrix()) & "," & LBound(vMatrix(), 2) & " To " & UBound(vMatrix(), 2) & ")"

' ' 下端2行を除いた二次元配列変数をすべて一括出力・例1(右端2列上記削除済)
Range("B404").Resize(UBound(vMatrix()) - 2, UBound(vMatrix(), 2)) = vMatrix()

' ' 下端2行を除いた二次元配列変数をすべて一括出力・例2(右端2列上記削除済)
vMatrix() = WorksheetFunction.Transpose(vMatrix()) ' 一旦、行列を入れ替え(Y,X → X,Y)
ReDim Preserve vMatrix(1 To 298, 1 To 198) ' 二次元配列をリサイズ(X,Y → X,Y-2)
vMatrix() = WorksheetFunction.Transpose(vMatrix()) ' 再度、行列を入れ替え、元に戻す(X,Y-2 → Y-2,X)
Range("B605").Resize(UBound(vMatrix()), UBound(vMatrix(), 2)) = vMatrix()
Debug.Print "#1 vMatrix(" & LBound(vMatrix()) & " To " & UBound(vMatrix()) & "," & LBound(vMatrix(), 2) & " To " & UBound(vMatrix(), 2) & ")"

' ' 配列変数をクリア
Erase vMatrix()
End Sub
' ' ///

差し当たり以上ですが、
不明、不足等ありましたら補足下さい。
先回のご質問も放置されたままでが
せめて「読んだ」と解るよう、ご一報ください。

投稿日時 - 2015-11-23 16:02:59

補足

お礼が遅れて申し訳ありませんでした。
質問後、二次元配列を使うのは不可能かと勘違いし、一次元配列で、処理しようと試みておりました。しかし、そちらもうまくいきそうになく、アドバイスいただいた内容をもう一度当てはめてみます。ありがとうございます。

投稿日時 - 2015-11-30 10:04:57

-広告-
-広告-

あなたにオススメの質問

-広告-
-広告-