• ベストアンサー

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)のようなことができればと思います。 よろしくお願いします。

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

  • ベストアンサー
  • KenKen_SP
  • ベストアンサー率62% (785/1258)
回答No.2

こんにちは、KenKen_SP です。 >WORKに貯めるのもめんどうなので、 テンポラリー配列を用意しなくても、ワークシート関数の INDEX を使えば 1行で済みます。 ご提示のコードで Long 型配列 DATA は Empty のまま転記されてますが、 これは何らかの処理の記載が省略されているだけですよね? 分かり易いように、A1:E1000 セルの値を配列化した場合のサンプルを記載 しておきます。 Sub Sample()   Dim Buf As Variant      ' (1) A1:E1000 セルのデータを配列化   Buf = Range("A1:E1000").Value   ' (1) で生成した配列において 3列目の全ての要素を取り出す   ' Worksheet Function の Index を使った例   ' 書式:Index(配列, RowIndex, ColumnIndex)   ' 1列全てを取り出す場合は、RowIndex を 0 にする   ' 次の例では、C1:C1000 の内容が G1:G1000 に転記される   Range("G1:G1000").Value = Application.Index(Buf, 0, 3) End Sub

QAZ123
質問者

お礼

教えていただいたINDEX命令により、目的が達成できました。 これで、テンポラリー配列を用意する手間が省けました。 ありがとうございました。

その他の回答 (2)

  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.3

こんにちは。 >RANGE("J1:K1000").VALUE = DATA(1,5), DATA(2,5), DATA(3,5),~,DATA(999,6),DATA(1000,6)のようなことができればと思います。 Ar を二次元配列の変数として、以下のようにすれば出来るけれども、 U = UBound(Ar, 2) Worksheets("Sheet2").Range("A1").Resize(, U).Value = WorksheetFunction.Index(Ar, 5, 0) >方法1)より(方法2)の方が早いのですが ということ自体にも、一体、どれほどの問題があるのか私には分かりません。 私個人は、上記のような、キワモノのコードはめったに書きません。しょせん、ワークシート上の問題は、ワークシート内で片付けるのが一番で、この場合は、Range オブジェクト変数に格納するほうが分かりやすいです。 それ以上の実験的な問題は、ここのような何でもありのQ&A掲示板ではなく、専門掲示板でお聞きになったほうがよいのではないか、と思います。例えば、レーシングカーのようにチューンしたものと、一般道を走る車とでは、その求める度合いが違います。 >すばやく書き戻す方法 >WORKに貯めるのもめんどうなので、 半年間のご質問を見させていただいて感じましたが、そういうことは、一通りすべてがこなせてからのほうがよいですね。また、基本の型や定石を覚えて、その上で発展していくのはよいのですが、最初から、定石外しをもくろみ、他力本願で、掲示板で応援を求めてしまうと、VBAは、単発のワザしか使えない人になってしまいます。 失礼かもしれませんが、そう感じました。

QAZ123
質問者

お礼

善意で質問に答えてくださる方に、大変失礼だとは思いますが、今回の場合はINDEXという命令語の存在を知りたかっただけなのですが、質問の方法に問題があるのでしょうか? VBAの定石を理解しているのかとたずねられると、当方は、当方に必要なVBAの知識しかないので、その知識にない部分をこのOKWAVEで質問しているだけで、実験的な問題や定石外しのために質問しているのではないのですが。 ともあれ、INDEX命令を教えていただき、ありがとうございました。 ひとつ、これからもよろしくお願いします。

  • hana-hana3
  • ベストアンサー率31% (4940/15541)
回答No.1

>WORKに貯めるのもめんどうなので、 配列で操作するのが一番高速で実行出来ます。 >RANGE("J1:K1000").VALUE = DATA(1,5), DATA(2,5), DATA(3,5),~,DATA(999,6),DATA(1000,6) 代入方法(=)としては意味を成していないので不可能です。 プログラムを短くすることは出来ますよ。 Dim WORK(1 to 1000,1 to 2) As Long FOR 行番号= 1 TO 1000 WORK(行番号,1) = DATA(行番号,5) WORK(行番号,2) = DATA(行番号,6) NEXT RANGE("J1:K1000").VALUE = WORK()

QAZ123
質問者

お礼

回答を付けていただき、ありがとうございました。 プログラムを短くすることができました。

関連するQ&A

  • EXCEL VBAの配列でわかりません。

    こんなコードがあるのですが、最後の他のシート(作業中シート)に書き込もうとするとエラーになってしまいます。”Sheets("作業中").”を抜くと同じシートに結果は返ってくるのですが…。コードの内容は、ある範囲のある列から空白ではないセルを探し出してその行のデータを配列で汲み取り、他のシートに一括で洗い出すというものです。 Sub 作業中() Dim myRow As Long Dim Data As Variant Dim WC() As Variant Dim WCE() As Variant myRow = Range("H1").CurrentRegion.Rows.Count Data = Range("H1:M" & myRow).Value For i = 1 To myRow If Data(i, 5) <> "" Then a = a + 1 Else b = b + 1 End If Next ReDim WC(a) ReDim WCE(b) c = 0 d = 0 For i = 1 To myRow If Data(i, 5) <> "" Then WC(c) = Range("H" & i & ":K" & i).Value c = c + 1 Else WCE(d) = Range(Cells(i, 8), Cells(i, 11)).Value d = d + 1 End If Next For i = 0 To a Range(Cells(i + 1, 15), Cells(i + 1, 18)).Value = WC(i) Next For i = 0 To b Range(Cells(i + 1, 19), Cells(i + 1, 22)).Value = WCE(i) Next e = Range(Cells(1, 15), Cells(a, 18)).Value Sheets("作業中").Range(Cells(1, 1), Cells(a, 4)).Value = e End Sub ちなみに同じシートから↓のコードを実行するとうまくいきます。 なぜ~??わからな~い??おしえてくださーい!! Sub test() Dim a As Variant a = Range("H1:K4") Sheets("作業中").Range("N1:Q4") = a End Sub

  • VBA ユーザーフォーム

    VBA初心者です。以下の様なソースを見つけました。この場合は、文字を検索するとD1 にその該当番号が表示されます。 ※A列には番号、B列には文字列 そうではなく、そのクリックした行のA列にセルが移動し、ユーザーフォームが閉じられる様にできますでしょうか? よろしくお願い致します。 Private Sub ListBox1_Click() Sheets("Sheet1").Range("D1").Value = ListBox1.Value End Sub Private Sub TextBox1_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean) Dim v() As Variant Dim c As Range Dim k As Long ListBox1.Clear With Sheets("Sheet1") With .Range("A1", .Range("A" & .Rows.Count).End(xlUp)) ReDim v(1 To 2, 1 To .Rows.Count) For Each c In .Cells If c.Offset(, 1).Value Like TextBox1.Value & "*" Then k = k + 1 v(1, k) = c.Value v(2, k) = c.Offset(, 1).Value End If Next If k = 0 Then MsgBox "指定の値は存在しません" Else ReDim Preserve v(1 To 2, 1 To k) ListBox1.List = WorksheetFunction.Transpose(v) End If End With End With End Sub

  • VBA セルの値を取得する

    下記のはランダムにチーム分けするものです。 TmCnt = 5がチーム数です。 Sub Sample() Dim Total As Integer Dim TmCnt As Integer Dim Data1 As Variant Dim Data2() As String Dim i As Integer, j As Integer, k As Integer Total = Cells(Rows.Count, 1).End(xlUp).Row TmCnt = 5 Data1 = Range("A1:A" & Total).Value ReDim Data2(1 To Total) Randomize For i = TmCnt To 1 Step -1 j = Int(Rnd * i) + 1 Data2(i) = Data1(j, 1) Data1(j, 1) = Data1(i, 1) Next i For i = Total To TmCnt + 1 Step -1 j = Int((i - (TmCnt + 1) + 1) * Rnd + TmCnt + 1) Data2(i) = Data1(j, 1) Data1(j, 1) = Data1(i, 1) Next i i = 1 Do For j = 1 To TmCnt k = k + 1 Cells(i, j + 2).Value = Data2(k) If k = Total Then Exit Sub Next j i = i + 1 Loop End Sub TmCnt = 5をセル「B1」にチーム数を入力し、(例「6」「4」など)マクロを実行したいのです。 検索しましたところ、 セルの値を取得するにはRange("A1").Valueを入力だそうです。 TmCnt = 5を下記に書き換えるにはどのようにしたら良いでしょうか? Dim s As String s = Range(“B1”).Value Debug.Print(s) 宜しくお願いします。

  • [VBA]二次元配列を使ったsumif

    こちらの識者の方々にはいつもお世話になっています。 VBAの質問です。 環境は下記になります。 OS=windowsXP SP3 Office=Excel2003(11.8347.8403) SP3 vbaでワークシート関数でいうsumifにあたる計算をしたいのですが、自分なりに二次元配列でコードを書いたものの、それでも時間がかかりすぎるため質問させていただきます。 :Sheet1      4月   5月   6月   7月 りんご  20    10   31 みかん  50        40    20 バナナ  35    15   20 りんご       52   50    65 ぶどう           32    63 みかん  21        23    50 のようなデータが約40,000行存在します。 これをSheet2に      4月   5月   6月   7月 りんご  20    62   81   65 みかん  71    0    63   70 バナナ  35    15   20    0 ぶどう  0     0   32    63 のような形で集計したいのです。 自分で書いたコードは下記です。 Option Explicit Option Base 1 Sub test()  Dim SourAry As Variant  Dim DestAry As Variant  Dim SourEndRow As Long  Dim DestEndRow As Long  Dim i As Long  Dim j As Long  Dim k As Long  Dim TTL As Long  Application.ScreenUpdating = False  SourEndRow = Sheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Row  DestEndRow = Sheets("Sheet2").Cells(Rows.Count, 1).End(xlUp).Row  SourAry = Sheets("Sheet1").Range("A2:E" & SourEndRow).Value  DestAry = Sheets("Sheet2").Range("A2:E" & DestEndRow).Value  For i = 2 To 5   For j = 1 To UBound(DestAry)    For k = 1 To UBound(SourAry)     If SourAry(k, 1) = DestAry(j, 1) Then TTL = TTL + SourAry(k, i)     DestAry(j, i) = TTL    Next k    TTL = 0   Next j  Next i  Sheets("Sheet2").Range("A2:E" & DestEndRow).Value = DestAry  Application.ScreenUpdating = True End Sub これでも一応希望通りの結果は得られるのですが、40,000行ともなると配列で処理したとしてもとても時間がかかってしまいます。 ご教示いただきたいことは、もっと効率のいいコードなのですが、実は実際のデータはSheet1とSheet2のA列のデータは昇順で並んでおります。 後学のためにもしよろしければ下記2パターンを教えて戴けませんでしょうか。 1.キーとなるフィールドが昇順で並んでいる場合 2.キーとなるフィールドの順番がばらばらで、かつ並び替えることができない場合(A列総当たり) 2.のパターンの場合、コードによると思いますが、総当たりよりかはやはり並び替えた方が効率はいいものなのでしょうか? 質問に不備不足等ございましたらご指摘ください。 ご面倒お掛けしますがよろしくお願いします。

  • VBAの動的配列について

    いつもお世話になっております。 エクセルVBAを学習中の者です。 動的配列についてお伺いします。 添付資料を見て頂きたいのですが、 シート名1~4に同一レイアウトの表があります。 これらの表をを2次元配列に格納し、その後、同一レイアウトのシートに一括転記したいと考えています。 転記の事を考えて、条件としては、 シート1から2行目以降のデータを配列『data』に格納、変数『dataCnt』が転記先の行番号と同じになるように考えています。 当初は、配列の定義を『Dim data(100,3) As Variant』と、多めに要素数を定義して、コードを記述していました。 正直、凄く気持ちが悪い感じでした・・・ 最近、動的配列を学習しまして、 シートごとにデータの行数を変数『lastRow』に格納して、配列を再定義して【データ数=要素数】とならないか? と思い、下記のようなコードを書いてみました。 が、『ReDim Preserve~』で実行エラーが発生してしまいます。 原因がなぜかわかりません! そもそも、動的配列はこのような使い方は出来ないのでしょうか? Sub テスト() Dim data() As Variant Dim x As Long Dim i As Long Dim ii As Long Dim lastRow As Long Dim dataCnt As Long dataCnt = 2 For x = 2 To 5 Worksheets(x).Activate lastRow = Cells(Rows.Count, 1).End(xlUp).Row If x = 2 Then ReDim data(2 To lastRow, 3) Else ReDim Preserve data(2 To dataCnt + lastRow - 1, 3) End If For i = 2 To lastRow For ii = 1 To 3 data(dataCnt, ii) = Cells(i, ii) Next ii dataCnt = dataCnt + 1 Next i Next x End Sub どなたかご指導をよろしくお願いいたします。

  • VBA なぜ配列にドカンと一発で入れることが出来る

    下に2つのコードを示していますが、パターン1は、配列cに一発で一気に速く入れることが出来る雰囲気が表れています。実際に速いそうです。 しかしながら、どちらのコードも、最終的には配列cに一つずつデータが入るわけですよね。 なぜ、パターン1だと速いのでしょうか? 専門的でむずかしいようでしたら、イメージだけでも教えていただけたらと思います。 パターン1 Dim r as Range Dim c() As Variant Set r=Selection c = r.Value パターン2 redim c(r.rows.count,r.columns.count) for i=1 to r.rows.count for j=1 to r.columns.count c(i,j)=r(i,j).value next j next i

  • Excel collectionについて VBA

    Dim Mydata As New Collection Dim i As Long Dim EndNumber As Long On Error Resume Next 'データを登録する間、エラーを無視する For i = 2 To EndNumber '2行目から最終行までチェック Mydata.Add Range("J" & i).Value, Range("J" & i).Value 'J列のデータ取得 Next i On Error GoTo 0 i = 1 For Each A In Mydata Worksheets("Sheet1").Range("A" & i).Value = A i = i + 1 Next A 現在見ているシートの重複しない項目を 別シートに書き込みしているプログラムになります。 様々なサイトを参考にさせて頂き、 上記のような結果になり、 文字列は取得できるようになりました。 しかし、もとになるデータがある位置に(例は、J列) 数値が入っていると上手くコレクションに入ってくれません。 J列に文字列(りんご、ごりらなど)が入っている場合は 重複しない項目がコレクションに格納されていきます。 J列に文字列(0,1)が入っていた場合、 重複しない項目もなにも無く、 ローカルのMydataの中には<変数無し>とありました。 このプログラムの何処を直せば、数値をコレクションとして取得できますか? ちなみに、EndNumberには最終行の数値が入っています。 >Mydata.Add Range("J" & i).Value, Range("J" & i).Value 'J列のデータ取得 .valueを.stringにしても効果はありませんでした。 回答よろしくお願いいたします。

  • ExcelのVBAの配列に関する質問です。

    ExcelのVBAの配列に関する質問です。 sheet1のデータをsheet2に表示するVBAを作成しています。。 sheet1のデータは7行目からスタートし、sheet2のデータは26行目からスタートしています。。 sheet1とsheet2の列は同じ並びではないため、それぞれのシートの列番号をCellsを用いて指定しています。 Sub test1() Dim endrow As Long endrow = Worksheets("sheet1").Range("A65536").End(xlUp).Row Dim i As Long Dim j As Long For i = 7 To endrow j = i + 19 Worksheets("sheet2").Cells(j, 1) = Worksheets("sheet1").Cells(i, 2) Worksheets("sheet2").Cells(j, 8) = Worksheets("sheet1").Cells(i, 28) Worksheets("sheet2").Cells(j, 9) = Worksheets("sheet1").Cells(i, 31) Worksheets("sheet2").Cells(j, 10) = Worksheets("sheet1").Cells(i, 32) ・ ・ ・ ※長いので省略 Next i End Sub 上記のtest1は正常に動くのですが、データ量が多いため、処理に時間がかかってしまいます。 高速化できないかと、以下のように変更しました。 Sub test2() Dim dataRange1 As Variant Dim dataRange2 As Variant dataRange1 = Worksheets("sheet1").Range("A1:GI10006") dataRange2 = Worksheets("sheet2").Range("A1:DZ10018") Dim endrow As Long endrow = Worksheets("sheet1").Range("A65536").End(xlUp).Row Dim i As Long Dim j As Long For i = 7 To endrow j = i + 19 dataRange2(j, 1) = dataRange1(i, 2) dataRange2(j, 8) = dataRange1(i, 28) dataRange2(j, 9) = dataRange1(i, 31) dataRange2(j, 10) = dataRange1(i, 32) ・ ・ ・ ※長いので省略 Next i End Sub test2は、エラーメッセージ等は表示されませんが、sheet2にデータが表示されません。 ちなみに、以下のようにsheet1のみ配列化した場合は、正常に表示されました。 Worksheets("sheet2").Cells(j, 1) = dataRange1(i, 2) Worksheets("sheet2").Cells(j, 8) = dataRange1(i, 28) Worksheets("sheet2").Cells(j, 9) = dataRange1(i, 31) Worksheets("sheet2").Cells(j, 10) = dataRange1(i, 32) test2は、どこが間違っているのでしょうか? ご教示ください。 よろしくお願いいたします。

  • エクセルVBA カウンタ2つを入れ子にしたくない時

    皆さんこんにちは。 エクセル2013を使用しております。 エクセルVBAの繰り返し処理について質問させていただきます。 下記のコードですと入れ子があるので A1にi、A3にi・・・・を一通り記載したあと またA1にi+2、A3にi+2・・・を繰り返し 最終的にA列には全て同じ値が入ってしまいます。 (Step 2にしたのはA1:A2のように2行毎の結合セルだからです) -----------------------------------------------------------------    Dim i As Long Dim j As long Dim n As long Dim k As long     i =Userform.textbox1.value     j =Userform.textbox2.value    For k =i To j Step 2 For n = 1 to j Step 2 Range("A" & n) = k    Range(”B”&n)=k+1        Next    Next ---------------------------------------------------------- もしiが1、jが10だとしたら A1に1、B1に2、A3に3、B3に4、・・・A9に9、B9に10 が入るようにするにはどうしたら良いでしょうか。 iが必ず1から始まるのであればまだ分かるのですが そうとも限らないので カウンタはやはり2つ必要だと思うのですが カウンタが2つあるのに入れ子にしないコードの書き方って あるのでしょうか。 いくら本やネットを見ても分かりません。 ご教授いただけると幸いです。

  • comboboxで任意の行列を削除する

    comboboxで選択したデーターを探して、その行の 2列目から45列までを、削除する方法をお教えください。 下のように記述したのですが、1行全てが削除されてしまいます。 どのように記述したらよいのでしょうか。 よろしくお願いします。 Private Sub 保存データー削除_Click() Dim i As Long For i = 2 To 199 If Cells(i, 2).Value = combobox1.Value Then Range(i & ":" & i).Delete End If Next i Dim k As Long, s As Long k = 1 For s = 1 To 31 Cells(s, 1).Value = k k = k + 1 Next s End Sub

専門家に質問してみよう