ExcelVBAでの配列処理について

このQ&Aのポイント
  • ExcelVBAで配列処理を利用したい場合、処理速度の向上が期待できます。しかし、配列をシートに書き出す際に起こる問題に悩んでいます。
  • 10000行×2列の乱数表データを配列として作成し、A列に1万行、D列に1万行書き出したいと考えています。
  • 処理速度向上のため、ループ処理ではなく一気に書き出したいです。解決方法を教えてください。
回答を見る
  • ベストアンサー

ExcelVBAでの配列処理について

処理速度向上を目的に配列を利用したいのですが、結果の書きだし処理で悩んでいます。 Dim aa(10000,2) as Double for i = 1 to 10000 for j = 1 to 2 aa(i,j)=Rnd() next j next i 上記の処理で、10000行と2列の乱数表データが配列として出来、そのデータをシートに書き出しするときに、列を2つほど飛ばして書き出したいのですが、どうすればよいのでしょうか? range("A1:B10000") = aa  という連続した列ではなく、A列に1万行、D列に1万行書き出したいと思っています。 処理速度を向上させたいので、またFor分処理するのではなく、一気に書き出したいと思っています。 ご教授のほどよろしくお願い申し上げます。

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

  • ベストアンサー
  • mitarashi
  • ベストアンサー率59% (574/965)
回答No.2

最初から列毎に分けて処理する事をお勧めします。(B,C列が0になってしまって良いなら別ですが) まとめて書き込んでいるので、Application云々の必要性は不明ですが、ご参考まで。 Sub test() Dim aa As Variant, ad As Variant Dim rngA As Range, rngD As Range Dim i As Long Const maxNo As Long = 10000 Randomize (Time) Application.ScreenUpdating = False Application.Calculation = xlCalculationManual Set rngA = Range("A1").Resize(maxNo, 1) Set rngD = Range("D1").Resize(maxNo, 1) aa = rngA ad = rngD For i = 1 To 10000 aa(i, 1) = Rnd() ad(i, 1) = Rnd() Next i rngA = aa rngD = ad Application.Calculation = xlCalculationAutomatic Application.ScreenUpdating = True End Sub

rj2011
質問者

お礼

ありがとうございます。 かなり高速に処理できそうです。 ただ、列数も可変の場合はもっとややこしいですよね。 教えていただいた方法で工夫すればできそうですが、別途ご教授していただけると助かります。

その他の回答 (5)

  • mitarashi
  • ベストアンサー率59% (574/965)
回答No.6

#2です。 列数が可変なら、どうせ一列ずつの処理ですので、自分なら次の様な関数にして、列毎に処理します。ここでは、先頭のセルと、データ数を渡す様にしてみました。 ご参考まで。 Sub test3(startCell As Range, maxNo As Long) Dim aa As Variant Dim rngA As Range Dim i As Long Randomize (Time) Application.ScreenUpdating = False Application.Calculation = xlCalculationManual Set rngA = startCell.Resize(maxNo, 1) aa = rngA For i = 1 To maxNo aa(i, 1) = Rnd() Next i rngA = aa Application.Calculation = xlCalculationAutomatic Application.ScreenUpdating = True End Sub

  • imogasi
  • ベストアンサー率27% (4737/17068)
回答No.5

確かにエクセルは、普通は画面のセルの値を修正を伴うのですが、それを Application.ScreenUpdating = False で抑止すれば、どちら(配列もセルも)もメモリへ書き込む処理になって、ForNextで書き込む(2列に分けてになる)のと、大きな差は無いのではないですか。自己満足ではないですかね。よく検証してみてください。結果的にセルの値を後ほどセットするならなおさら。 >処理速度を向上させたいので、なんていっているが質問者はプログラムのベテランですか?観念的な考えで左右されないように、テストでもして、実証しつつ、考えられんことを。 私はInsideエクセルのことは知りませんが(普通の人はこの点勉強して無いでしょう)。

rj2011
質問者

お礼

当然こういったサイトに技術的なことを質問しているぐらいですからベテランではありませんよ。 皆様のおかげて処理速度が速くなりました。 ありがとうございました。

  • mitarashi
  • ベストアンサー率59% (574/965)
回答No.4

#2です。 #3さんの手がありましたね。.Value=.Valueを入れないで、再計算に入り悲惨な目にあった事を思い出しました。 試みに、60000行にして処理時間を計測してみました。当方PentiumM1.33Gという古いマシン、xl2000です。 #2のコードで、実行2~6回目の平均時間が448msec、改造して#3さんの方法を取り入れたもので、511msecと、配列による方法も満更でもない結果でした。 ところで、For i = 1 to 10000 のところは、to maxNo の直し損ねですので、言わずもがなですがお知らせしておきます。(恥)

  • hallo-2007
  • ベストアンサー率41% (888/2115)
回答No.3

お役にたてるかどうかですが >処理速度を向上させたいので、またFor分処理するのではなく、一気に書き出したいと思っています。 With Range("A2:A10000") .FormulaR1C1 = "=RAND()" .Value = .Value End With With Range("D2:D10000") .FormulaR1C1 = "=RAND()" .Value = .Value End With といった方法では如何でしょうか。

rj2011
質問者

お礼

ありがとうございます。 これは早いですね。 こんなやり方があったとは知りませんでした。 この方法でも検討してみます。

  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.1

私なら一次配列に入れ直すか、最初から10000x4の配列を使って1と4だけ値を入れることを考えます。 後者の場合、こんな感じになりますか。 Dim aa(10000, 4) as double for i = 1 to 10000 for j = 1 to 4 step 3 aa(i, j) = Rnd() next j next i メモリをバカ食いするので配列サイズによっては不可能ですが、これくらいならたぶんなんとか。

rj2011
質問者

お礼

ありがとうございます。 1次配列に入れ直す方法も教えてもらえると助かります。

関連するQ&A

  • VBAの乱数について質問

    乱数 x (0<x<1)を0.1刻みで発生させたいんですが うまくいきません。 プログラム例 Sub 一様乱数() Dim bin#(10) n = 1000 For m = 1 To 10 bin#(m) = 0 Next m For J = 1 To n x = Rnd(1) ix = Int(10 * Rnd(1)) bin#(ix) = bin#(ix) + 1 Next J Cells(4, 1) = " I" Cells(4, 2) = "Bin#(I)度数分布" For I = 0 To 10 Cells(I + 5, 1).Value = I Cells(I + 5, 2).Value = bin#(I) Next I End Sub ここで、9行目ix = Int(10 * Rnd(1))で0.1刻みになり 15行目のFor I = 0 To 10を0 to 1に変えればできると思ったんですが できませんでした。 どこが問題なのかヒントでもいいので教えてください。

  • VBA配列 印のついた列番号を格納して利用したい

    Excel VBAで下記処理を作成しました。配列を使えば処理が高速化できるのでは?と思い調べたのですが、配列を使ったことが無く、挫折しましたのでどなたかご教示いただけませんでしょうか。 <対象データ>(添付画像の黄色いセルが処理対象) ・処理対象の行は「区分」列に「0」が入っている ・処理対象の列は、1行目に「●」が入っている <作成した処理> ・ループ(1):データ開始行(画像では3行目)から順に見ていく  ・IF:「区分」列が「0」なら下記に進む(0以外なら次の行へ)   ・ループ(2):列を左から順に見ていく    ・IF:その列の1行目が「●」なら処理を行う For i = 3 To 10000 If Cells(i , 1) = 0 And Cells(i , 1) <> "" Then その行に対する処理の下準備のコード(記載省略) For j = 2 To 500 If Cells(1 , j) = "●" Then Cells(i , j)に対する処理(記載省略) End If Next j End If Next i <問題点> データ量が数千行×数百列と相応にあるため、処理実行に数秒かかります。今後、処理をより複雑にしたいため、高速化できないかと考えています。 <質問> 対象行について毎回、ループ(2)で各列の1行目を調べて●だったら処理する、としているのが非効率かも知れないと思いました。 1行目に●が入っている列番号を調べるのは1度で良いので、それを配列に格納して、ループ(2)の部分で使うことはできますでしょうか? ご存じの方、ご教示いただけますと幸いです。よろしくお願いいたします。

  • 書き出し処理速度について

    バイナリデータを読み込み、数値データに変換、テキストファイルにタブ区切りで書き出すプログラムをvba/excelにて作成中ですが、書き出し処理速度の遅さに困惑しております。数値データに変換した配列はDATA(256,120000)としており、書き出しデータ数は約3,000,000個あります。その書き出しプログラムを下記のように記述したのですが、とんでもなく処理速度がおそいのです。   Open "c:\test.txt" For Output As #2 For i = 1 To 120000 For j = 1 To 256 Print #2, DATA(j, i); Chr(9);     Next j  Print #2, Chr(10); Next i Close #2 対処方法をご存知でしたら、ご教授願います。

  • エクセルVBAの配列について

    エクセルVBAの配列について VBAをはじめたばかりの初心者です。 現在、下記のようにデータを配列の中に入れ、 別シートに書き出そうとしております。 (配列へ読み込むところのみ) Dim 配列(1 To 件数, 1 To 9) As Variant For j =1 To 件数 For i = 2 To L If Cells(i, 2).Value = Tx_month Then For k = 3 To 11 配列(j, k - 2) = Cells(i, k).Value Next k End If Next j,i 現状では、データの最終行のみを「件数」分書き出してしまいます。 jとiのForが重なっているからだと思うのですが、どう書き直したら良いか分かりません。 質問をさせていただくのも初めてなので、分かりづらく恐縮ですが お力添え頂けますと幸いです。 どうぞ宜しくお願い致します。

  • VBA処理速度の向上(配列?)

    いつもお世話になっております。 エクセルVBA勉強中の初心者です。 書籍などを参考に、下記コードを作成し、セル内データを計算しています。 セル数が少ない場合には良かったのですが、将来的には、 約30,000行×100列程度になる予定で、処理に時間がかかってしまっています。 (現状で10,000行×50列程度、データは増えていきます。) 過去ログ、HPなどを調べると、配列に入れれば、処理速度が格段に上がると あったのですが、如何せん私には難しく、理解できませんでした・・・ 配列に限らず、処理速度が上がる方法をご教授、添削頂ければ助かります。 よろしくお願いいたします。 Sub test() Dim Gyo As Long, Retu As Long For Gyo = 3 To Range("A65536").End(xlUp).Row For Retu = 1 To Range("D3").End(xlToRight).Column Cells(Gyo, Retu).Value = Cells(Gyo, Retu).Value / 1000000 Next Retu Next Gyo End Sub

  • VBAの配列の格納について

    エクセルのVBAで、セルのデータを配列に格納するスピードを向上したいと思います。 例えば、A1~A10000のセルにデータを書き出す場合、 For 行番号 = 1 To 10000 Cells(行番号, 1).Value = 1 Next よりも、一旦、配列に書き込んだ後、一気にセルに書き込んだ方法が早いのですが、 For 行番号 = 1 To 10000 HAIRETU(行番号, 1) = 1 Next Range("A1:A10000").Value = HAIRETU() 今度は、A1~A10000に書き込んだデータを、再度、配列に格納する場合、 For 行番号 = 1 To 10000 HAIRETU(行番号, 1) = Cells(行番号, 1).Value Next とすると時間がかかるので、 HAIRETU() = Range("A1:A10000").Value というような処理をしたいのですが、うまくいきません。 よい方法がありましたら、ご教授ください。 よろしくお願いします。

  • AWKの配列内データの処理について

    AWKを使用して入力ファイルの1行内の単語に対して条件チェックするには for( i=1 ; i<= NF i++ ){    if( $I == chek_word )       処理 } とすればできるのはわかるのですが、 一旦、配列の中に格納した文字列に対して上記の処理と同様の処理をするにはどのようにすればいいのでしょうか? 例えば data_line[$1] = $0; として配列data_lineに格納した1行そのままのデータに対して1番上の行全体にわたる単語の条件チェック をおこないたいのですが、どのようにすればいいのかよくわかりません。 どなたかご存知の方アドバイスをお願いします。

  • ExcelVBAでデータを一括してセルに貼り付ける

    こんばんは ExcelVBAで教えてください。 配列のデータをセルに貼り付ける方法です。 一つ一つ行う方法は解ります。 しかし、これでは件数が多いと時間がかかってしまいます。 まとめて貼り付ける方法を教えてください。 例えば次のように100列1000行のデータのとき、一つ一つでは10万回も貼り付けることになります。 これを1行単位で1000回とか全部まとめて1回とかでできないでしょうか。 配列データを用意する都合で1行単位もお願いします。 For Row = 1 To 1000 For Column = 1 To 100 Cells(Row, Column).Value = 配列(Row - 1, Column - 1) Next Next

  • VBAで、配列のデータをセルに書き戻す方法について

    1000行200列の配列があり、配列の5列目と6列目のデータを、セルの10列目と11列目にすばやく書き戻す方法を教えてください。 (方法1) Dim DATA() As Long ReDim DATA(1 To 1000, 1 To 200) FOR 行番号= 1 TO 1000 CELLS(行番号,10).VALUE = DATA(行番号,5) CELLS(行番号,11).VALUE = DATA(行番号,6) NEXT (方法2) Dim DATA() As Long ReDim DATA(1 To 1000, 1 To 200) Dim WORK1() As Long ReDim WORK1(1 To 1000, 1 To 1) Dim WORK2() As Long ReDim WORK2(1 To 1000, 1 To 1) FOR 行番号= 1 TO 1000 WORK1(行番号,1) = DATA(行番号,5) WORK2(行番号,1) = DATA(行番号,6) NEXT RANGE("J1:J1000").VALUE = WORK1() RANGE("K1:K1000").VALUE = WORK2() (方法1)より(方法2)の方が早いのですが、WORKに貯めるのもめんどうなので、 RANGE("J1:K1000").VALUE = DATA(1,5), DATA(2,5), DATA(3,5),~,DATA(999,6),DATA(1000,6)のようなことができればと思います。 よろしくお願いします。

  • VBA 配列計算について 配列の入力に配列の使用

    配列に複数のセル値の合計値を設定したいと思っています。 求める合計値は複数あるため、出力も配列となります。 そこで下記のようにプログラムを考えたのですが、全て同じ値の配列として出力されてしまいます。 VBAではC言語のように配列の古い値に足していくことはできないのでしょうか? (sum()は0で初期化) (10個飛ばしのデータの合計値を算出) For i = 0 To 10 For j = 0 To 5 sum(i)= sum(i) + Worksheets(sheetname).Cells(10, 3).Offset(j * 10, 0).Value Next i Next j 出力配列例 全て同じ値になってしまいます・・・ 1.254 1.254 1.254 ・・・ 回避方法もしくはうまい計算方法などありませんでしょうか

専門家に質問してみよう