• 締切済み

配列変数に格納したデータを計算する方法はありますか?

 簡単な例ですが、例えばB列にあるデータの平均値を求めるときに以下のようにしています。 sub 平均計算()   Dim X(1 To 1000, 1 To 1) As Variant, i as Integer   For i = 10 To 1000     X(i, 1) = WorksheetFunction.Average _          (Range(Cells(i - 9, 2), Cells(i, 2)))   Next   Range(Cells(1, 1), Cells(1000, 1)) = X End Sub  ここで処理速度改善のため、B列のデータを別の配列変数Yに格納してから平均値を求めるというようなことをしたいのですが、そんなことは可能でしょうか?イメージとしてはこんな感じです。   Y = Range(Cells(1, 2), Cells(1000, 2))   for i = 1 to 1000     X(i, 1) = WorksheetFunction.Average _          (Range(Y(i - 9, 2), Y(i, 2)))   Next  当然これはエラーになってしまいますが、このようなことを可能にする方法があれば、どなたか教えてください!よろしくお願いします。

みんなの回答

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

こんにちは。 配列を使えば必ず高速化できるわけではないです。ご質問文の 例だと下記の方が早いと思いますよ。 しかし、コンマ何秒とか数秒の高速化が必要な状況なのですか? 私なら体感できないほどの高速化なら、ソースの可読性を優先 させますが。。 Sub TestProc()   With Range("A10:A1000")     .FormulaR1C1 = "=AVERAGE(R[-9]C[1]:RC[1])"     .Value = .Value   End With End Sub

  • Gocho_
  • ベストアンサー率50% (1/2)
回答No.6

セル範囲は配列ではないVariant型に代入することが出来ます。 ちなみ処理速度は、セル参照型と変数参照型で約2倍の差が出ました。 私の環境でっていう条件ですが・・・・ Option Explicit Sub Test() Dim X(1 To 1000, 1 To 1) As Variant Dim Y As Variant Dim i As Integer Dim j As Integer Dim STime As Single '処理開始時間の処理 STime = Timer '連続したセル範囲の値を変数に代入 Y = Range("B1:B1000").Value '処理時間が早すぎて比較しづらいため、同じ処理を100回繰り返す For j = 0 To 100 For i = 10 To 1000 '変数に格納した値を参照(参考値 0.34375 秒) X(i, 1) = WorksheetFunction.Average(Y(i, 1), Y(i - 1, 1), Y(i - 2, 1), Y(i - 3, 1), Y(i - 4, 1), Y(i - 5, 1), Y(i - 6, 1), Y(i - 7, 1), Y(i - 8, 1), Y(i - 9, 1)) 'セルの値を参照(参考値 0.7192383 秒) 'X(i, 1) = WorksheetFunction.Average(Range(Cells(i - 9, 2), Cells(i, 2))) Next i Next j Sheet1.Range(Cells(1, 1), Cells(1000, 1)) = X Debug.Print Timer - STime End Sub <蛇足> 処理速度は速いですが、コーディングの観点から言えば、褒められません。 視認性が著しく低下し、何をしているのかがわかりにくくなります。 コードを作成者しか見ない場合は問題ないでしょうが、 そうでない場合はコメントでなぜこんな書き方をしているのか わかりやすく理由を記述しておくとよいと思います

  • end-u
  • ベストアンサー率79% (496/625)
回答No.5

>hige_082さん >前者であれば、配列や関数を使用するより、シンプルなものの方が・・・ ぉおー。なるほど、確かに速いですね。 Sub try5()   Dim v   Dim w   Dim x(10 To n, 1 To 1)   Dim i As Long   Dim t As Single   t = Timer   v = Range("A1").Resize(n).Value   For i = 1 To 10     w = w + v(i, 1)   Next   x(10, 1) = w / 10   For i = 11 To n     w = w + v(i, 1) - v(i - 10, 1)     x(i, 1) = w / 10   Next   Range("G10").Resize(n - 9).Value = x   Debug.Print "try5", Timer - t End Sub ありがとうございます。勉強になりましたm(_ _)m #また修行のタビに出なくちゃ...

  • hige_082
  • ベストアンサー率50% (379/747)
回答No.4

処理速度改善?それとも配列の練習? 前者であれば、配列や関数を使用するより、シンプルなものの方が・・・ Sub test() Dim i, ii As Integer Dim x As Integer ii = 0 x = 0 For i = 1 To 1000 x = x + Cells(i, 2) ii = ii + 1 Next MsgBox x / ii End Sub 速いかなと思っただけです 忘れてください お邪魔しました

okranta
質問者

お礼

確かにシンプルで速いですね。参考にさせてもらいます。皆さんに回答して頂く度にいろいろなやり方があることに気付かされます。ありがとうございます!

  • end-u
  • ベストアンサー率79% (496/625)
回答No.3

ぁー…すみません、ムダなLoopしてました。 '------------------------------------------------- Sub try3改()   Dim v   Dim w(0 To 9)   Dim x(10 To n, 1 To 1)   Dim i As Long   Dim j As Long   Dim t As Single      t = Timer   v = Range("A1").Resize(n).Value   With WorksheetFunction     For i = 0 To 9       w(i) = v(i + 1, 1)     Next     x(10, 1) = .Average(w)     For i = 11 To n - 9 Step 10       For j = 0 To 9         w(j) = v(i + j, 1)         x(i + j, 1) = .Average(w)       Next     Next   End With   Range("F10").Resize(n - 9).Value = x   Debug.Print "try3改", Timer - t End Sub '-------------------------------------------------

okranta
質問者

お礼

多くの例を示して頂いてありがとうございます。いろいろとやり方があるんですね。これを参考にして検証させてもらいます。どうもありがとうございました!

  • end-u
  • ベストアンサー率79% (496/625)
回答No.2

別配列に取得した後に、もうひとつ別サイズの配列にLoopで格納し計算させる事はできますが...... いろいろ試してみるのもいいかもしれませんね。 Option Explicit Const n = 60000 'テストデータ行数 '------------------------------------------------- Sub pre() 'テストシート作成   With Sheets.Add.Range("A1").Resize(n)     .Formula = "=rand()*" & n     .Value = .Value   End With End Sub '------------------------------------------------- Sub try1()   Dim x(10 To n, 1 To 1) As Variant   Dim i As Long   Dim t As Single      t = Timer   For i = 10 To n     x(i, 1) = WorksheetFunction.Average _          (Range(Cells(i - 9, 1), Cells(i, 1)))   Next   Range("B10").Resize(n - 9).Value = x   Debug.Print "try1", Timer - t End Sub '------------------------------------------------- Sub try2()   Dim r As Range   Dim x(0 To n - 10, 1 To 1)   Dim i As Long   Dim t As Single      t = Timer   Set r = Range("A1:A10")   With WorksheetFunction     For i = 0 To UBound(x)       x(i, 1) = .Average(r.Offset(i))     Next   End With   Range("C10").Resize(n - 9).Value = x   Set r = Nothing   Debug.Print "try2", Timer - t End Sub '------------------------------------------------- Sub try3()   Dim v   Dim w(0 To 9)   Dim x(1 To n - 9, 1 To 1)   Dim i As Long   Dim j As Long   Dim t As Single      t = Timer   v = Range("A1").Resize(n).Value   With WorksheetFunction     For i = 1 To n - 9       For j = 0 To 9         w(j) = v(i + j, 1)       Next       x(i, 1) = .Average(w)     Next   End With   Range("D10").Resize(n - 9).Value = x   Debug.Print "try3", Timer - t End Sub '------------------------------------------------- Sub try4()   Dim t As Single      t = Timer   With Range("E10").Resize(n - 9)     .Formula = "=average(A1:A10)"     .Value = .Value   End With   Debug.Print "try4", Timer - t End Sub

  • n-jun
  • ベストアンサー率33% (959/2873)
回答No.1

>Range(Y(i - 9, 2), Y(i, 2)) 配列Yがマイナス(1-9=-8)になるのは変ですし、Yには値が入りますので、 Range型にもならないのでは? 10行を1行ずつずらした場合、1~1000行なら回数は991回だと思うのですが・・・ Sub test() Dim r As Range Dim i As Integer Dim v(1 To 991, 1 To 2) As Variant Set r = Range("B1:B10") For i = 1 To 991 v(i, 1) = WorksheetFunction.Average(r) v(i, 2) = r.Address Set r = r.Offset(1) Next Range("C1:D991").Value = v End Sub 違ってたらスル~して下さい。

okranta
質問者

補足

おっしゃる通りWorksheetFunction.Average(Range(Y(i - 9, 2), Y(i, 2))) という表記は実行するとエラーになります。 このようなことが出来ればいいな、ということで記載しました。 教えていただいた方法を参考にして検証してみます。

関連するQ&A

  • ■VBA■ SUMとAVERAGEの違い

    A列に5分毎のデータが並んでいて、このデータの30分毎の平均や合計をB列に出力したいとします。 このとき、以下のマクロを実行すると 「WorksheetFunctionクラスのAverageプロパティを取得できません。」 というエラーが出てしまいます。 Dim i As Integer For i = 1 To 1000 Cells(7 + i, 2).FormulaR1C1 = Application.WorksheetFunction.Average(Range(Cells(1 + 6 * i, 1), Cells(6 + 6 * i, 1))) Next しかし、Averageの部分をSumにすると実行できるのです。。。 なぜでしょうか????? それから、5分毎のデータを30分毎のデータに変換する良い方法があったらそちらも加えて教えてください!!

  • VBA 配列に格納した値の平均のやり方についてお教え願います

    いつもお世話になります。 配列に格納した値の平均のやり方についてお教え願います。 現在、実験測定データの移動平均(下記avg(x,1))を計算をしたいのですが、 配列に格納した値の平均が思うように計算できず困っております。 a =Range("A1:A20000")‘測定データを配列に格納 avg(x, 1) = Application.WorksheetFunction.average(a(x, 1), a(x + 5, 1)) という記述方法ではa(x, 1)とa(x + 5, 1)の2点の平均になってしまいます。 これをa(x, 1), a(x+1, 1),a(x+2, 1),a(x+3, 1) ,a(x+4, 1) ,a(x+5, 1)の5点の平均が計算できる記述方法はないでしょうか? ○実際の式は下のようなもので移動平均の平均区間yも変化します。 Dim avg(1 To 20000, 1 To 1) -前式省略- For y = 1 To 20000 -途中式省略- a =Range("A1:A20000")‘測定データを配列に格納 For x = 1 To 20000 avg(x, 1) = Application.WorksheetFunction.average(a(x, 1), a(x + y, 1)) ‘↑これでは2点の平均値になってしまいます。 Next -途中式省略- Next -後式省略- ○Range(“B1”)=AVERAGE(A1:OFFSET(A1,y-1,0)) Range(“B2”)=AVERAGE(A2:OFFSET(A2,y-1,0))  ・・・ というふうにセルに一つずつaverage関数を入力すれば移動平均も計算できるのですが、繰り返し回数が多いため、計算に非常に時間がかかります。そのため上記配列を利用したもので計算したいと思います。 ○ ネットでヒントを見つけたのですが↓ Set ran = Range(Range("A1"), Range("A1").End(xlDown)) Range("C4").Value = WorksheetFunction.average(ran) こう記述すればある範囲内の平均を求められるようですが、 Set ran= 以降の部分をRange(***)ではなく、 Set ran = (a(x, 1), a(x + y, 1)) ←a(x, 1)~a(x + y, 1)まで、というイメージですが・・・ というふうに範囲を配列で表すやり方を教えて頂けるだけでも結構です。 excel2003です。 以上、よろしくお教え願います。

  • 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] CountIfに変数を使いたい

    ある数値データがA1:A100まであるとします。これをいくつかの変数に基づいて数えたい場合、どうしたらいいのでしょうか? x=1 For i = 1 To 10 Cells(i, 5) = WorksheetFunction.CountIf(Range("A1","A100),">-(x)") x=x+10 Next i のような式を作ったんですが、うまく働いてくれません。たぶん変数xが使えないからだと思いますが、他にいい方法が浮かびません。いい方法がありましたら教えてください。よろしくお願いします。

  • rangeメソッドは失敗しました

    またまたエラーが起きてしまいました、、 D列にある数値の平均値を出すマクロを組みたいのですが そのD列は今後増えていくので変数を使い指定したいのです Option Explicit Public Sub all() Const SH_NAME As String = "VBA" Dim i Dim endrow As Long Dim ws As Worksheet Dim Result As Integer Set ws = ThisWorkbook.Worksheets(SH_NAME) With ws endrow = .Cells(Rows.Count, 4).End(xlUp).Row For i = 2 To endrow Result = Application.WorksheetFunction.Average(.Range("D2:D&i")) .Range("F39").Value = Result .Range("F39").NumberFormatLocal = "0.00" Next i End With End Sub このコードだと Result = Application.WorksheetFunction.Average(.Range("D2:D&i")) のところでrangeメソッドは失敗しました と言われてしまいます どうかよろしくお願いします<m(__)m>

  • 配列に格納したデータを指定行以下に転記する方法

    excel2000を使っています。 以下のコードだと最終行にデータが転記されます。これを4行目に確定して、転記したいのです。常に4行目つまりA列4行目以下に上書きしたいのです。 その場合コードをどのように変更すべきでしょうか? Sub 配列() With ActiveSheet ' 配列に格納 --------------------------- Dim i As Integer Dim LastRow As Long Dim SaleAry As Variant ' 配列に格納 --------------------------- SaleAry = Array(.Range("t4"), .Range("e5"), .Range("g5"), .Range("o5")) End With ' 転記 --------------------------- With Worksheets("daityou") LastRow = .Range("A65536").End(xlUp).Row For i = 0 To UBound(SaleAry) .Cells(LastRow + 1, i + 1).Value = SaleAry(i) ' Next i End With Set SaleAry = Nothing End Sub

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

  • For~Nextの使い方

    こんにちは Range("B19").Value = Application.WorksheetFunction.Sum(Range("B4:B17")) Range("B55").Value = Application.WorksheetFunction.Sum(Range("B40:B53")) Range("B91").Value = Application.WorksheetFunction.Sum(Range("B76:B89")) Range("B127").Value = Application.WorksheetFunction.Sum(Range("B112:B125")) 上記を参考書等で見ながらやって見たのですが 動作しません。 For~Nextの使い方を教えて下さい。 Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range) Dim x As Long, g As Long For x = 19 To 127 Step 36 For g = 4 To 112 Step 36 Cells(x, "B").Value = Application.WorksheetFunction.Sum(Cells(g, "B")) Exit For Next Next End Sub

  • エクセルマクロ配列で変数は使えますか

    エクセル2013です。 初めて配列を使います。 以下のように作成し思ったようにできました。 Sub 計算() '成功 Dim a As Integer Dim c As Integer Dim b(5) As Integer Dim 最終行 Dim 値列  値列 = 17 最終行 = Cells(Rows.Count, 1).End(xlUp).Row For 処理業 = 1 To 最終行 For a = 1 To 5 b(a - 1) = Cells(1, 値列) 値列 = 値列 + 1 Next 値列 = 17 For a = 1 To (22 - 値列) c = c + b(a - 1) Next Cells(処理業, 30) = c a = 0 c = 0 Next 処理業 End Sub ただ計算する列の範囲をインプットボックスで入力した値 にしたい為以下のように改造しました。 Dim b(対象列) As Integerでエラーになります 配列には変数は使用できないのでしょうか? よろしくお願いします。 Sub 計算() '失敗 Dim a As Integer Dim c As Integer Dim b(対象列) As Integer’★ここでERRになる Dim 最終行 Dim 対象列 Dim 値列  対象列 = 22'インプットボックスで入力した値 値列 = 17 最終行 = Cells(Rows.Count, 1).End(xlUp).Row For 処理業 = 1 To 最終行 For a = 1 To (対象列 - 17) b(a - 1) = Cells(1, 値列) 値列 = 値列 + 1 Next 値列 = 17 For a = 1 To (22 - 値列) c = c + b(a - 1) Next Cells(処理業, 30) = c a = 0 c = 0 Next 処理業 End Sub

  • VBA sheet2データーから平均取得 sheet1へコピー

    sheet2指定セルデーターから平均 sheet1指定セルに取得したいのですがうまくいきません。 例 sheet1       sheet2 列A  列B 列C  列A  列B 列C 1  2 指定  1  2  3 1  2  3   1  2  3 1  2  3   1  2  3 sheet2・列C1~3の平均を、sheet1・指定セルに取得したいのですが Sub test() Dim r As Long, u As Long, ws1 As Object, ws2 As Object, y As Long r = 10 u = 1 Set ws1 = Sheets(1) Set ws2 = Sheets(2) y = ws1.Range("A" & Rows.Count).End(xlUp).Row Dim myAve As Long myAve = Application.WorksheetFunction.Average(ws2.Range(Cells(3, u), Cells(7, u))) ws1.Cells(r, 7).Value = "myAve" r = r + 1 u = u + 1 End Sub 変数y r u を使いfor~nextでデーターを一括取得するつもりなのですが この段階でうまくいきません。

専門家に質問してみよう