Excel VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


746 / 13645 ツリー ←次へ | 前へ→

【78581】大容量Dataのシート間のコピーについて VBA初心者 16/11/18(金) 10:42 質問[未読]
【78585】Re:大容量Dataのシート間のコピーについて 亀マスター 16/11/18(金) 17:14 回答[未読]
【78586】Re:大容量Dataのシート間のコピーについて β 16/11/18(金) 19:03 発言[未読]

【78581】大容量Dataのシート間のコピーについて
質問  VBA初心者  - 16/11/18(金) 10:42 -

引用なし
パスワード
   初めまして、自分の仕事でどうしても大容量のDataのコピーをしたいのですが
処理に非常に時間(1時間程度)がかかってしまい、困っております。
現実的にこれぐらいのData量を処理するのにどれくらいで出来るかのがわかっていないので的違い質問だったらすみません。

まだ、VBAを始めたばかりで、アドバイス頂けると助かります。

それでは、よろしくお願いします。


○やりたいこと
コピー元(Sheet1)が、45000行で16列の16進数があり、
それをコピー先(Sheet2)には3行ずつを1行に纏めて、15000行で48列という形に
変更したいのです。

○自分が作ったソース

Sub Macro1()
'
' Macro1 Macro
'


Dim t As Single
Dim m(800000) As String
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Set ws1 = Worksheets("Sheet1")
Set ws2 = Worksheets("Sheet2")

t = Timer
'
' Prevents screen refreshing
  Application.ScreenUpdating = False
' Prevents auto recalculation
  Application.Calculation = xlCalculationManual

n = 0
v = 0

For j = 1 To 45000
DoEvents
  For i = 0 To 15
    m(n) = ws1.Cells(1 + j, 1 + i)
    n = n + 1
  Next i
  ' Shows progress situation
    Application.StatusBar = "Processing " & j & " row"
Next j

For u = 1 To 15000
DoEvents
  For l = 1 To 48
    ws2.Cells(1 + u, l) = m(v)
    v = v + 1
  Next l
    ' Shows progress situation
    Application.StatusBar = "Processing " & u & " Write"

Next u


'下記のプログラムだと9344.96秒かかってしまうので、配列処理に変更
'For j = 0 To 15499
'DoEvents
'   For i = 0 To 47
'    If i < 16 Then
'      ws2.Cells(2 + j, i + 1) = ws1.Cells(2 + 3 * j, 1 + i)
'    ElseIf i < 32 Then
'      ws2.Cells(2 + j, i + 1) = ws1.Cells(3 + 3 * j, i - 15)
'    Else
'      ws2.Cells(2 + j, i + 1) = ws1.Cells(4 + 3 * j, i - 31)
'    End If
'Next i
'  ' Shows progress situation
'    Application.StatusBar = "Processing " & j & " row"
'Next j

'Next i' Restore recalc setting
  Application.Calculation = xlCalculationAutomatic

Debug.Print "処理時間は " & Round(Timer - t, 2) & " 秒です。"

End Sub

【78585】Re:大容量Dataのシート間のコピーについて
回答  亀マスター  - 16/11/18(金) 17:14 -

引用なし
パスワード
   実はセルのデータを読み込んだり書き込んだりというのは結構負荷がかかるものであり、このように大量のセルをひとつひとつ操作していると時間がかかります。
そこで、セルの読み書き回数を減らすために、セル範囲をバリアント型の変数に読み込んで操作し、最後にセルに戻すというのが常套手段です。

具体的には、

Dim v1 As Variant, v2 As Variant

v1 = Range("A1:P45000")
v2 = Range("A1:AV15000")

'v1、v2を配列と見なして操作
'例)v2(1, 5) = v1(2, 3)

Range("A1:AV15000") = v2
Range("A15001:P45000").Clear

これならセルを操作するのが4回だけなので、かなり高速化できると思います。

【78586】Re:大容量Dataのシート間のコピーについて
発言  β  - 16/11/18(金) 19:03 -

引用なし
パスワード
   ▼VBA初心者 さん:

こちらで45000行16列、各セル 16文字 のデータを作成し以下のコードを走らせると、
こちらの環境で 3秒弱です。
なので、ステータスバーの表示をするまでもないと思います。(コードではしていません)
DoEventsも不要です。

ただ、出来上がりのブックは10メガほどになりますね。
これって、ブックそのものの扱いが重そうですね。

Sub Test()
  Dim t As Double
  Dim ws1 As Worksheet
  Dim ws2 As Worksheet
  Dim fV As Variant
  Dim tV() As String
  Dim i As Long
  Dim y As Long
  Dim x As Long
  Dim j As Long
  Dim z As Long
  Dim flg As Boolean
  
  t = Timer
  
  Set ws1 = Sheets("Sheet1")
  Set ws2 = Sheets("Sheet2")
  
  fV = ws1.Range("A1", ws1.Range("A" & Rows.Count).End(xlUp)).Resize(, 16).Value
  ReDim tV(1 To UBound(fV, 1), 1 To 16 * 3)
  
  For i = 1 To UBound(fV, 1) Step 3
    x = 0
    z = z + 1
    For y = i To i + 2
      If y > UBound(fV, 1) Then
        flg = True
        Exit For
      Else
        For j = 1 To UBound(fV, 2)
          x = x + 1
          tV(z, x) = fV(y, j)
        Next
      End If
    Next
    If flg Then Exit For
  Next
        
  ws2.Range("A1").Resize(z, UBound(tV, 2)).Value = tV
  
  MsgBox Timer - t
  
End Sub

746 / 13645 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
2610219
(SS)C-BOARD v3.8 is Free