返回列表 上一主題 發帖

[發問] 請教要如何使用 VBA 判別不規則儲存格的辦法2

回復 29# ML089
謝謝你詳盡的說明,剛才我已全部使用 Debug 跑了一圈,
不明瞭處亦已由Debug中得到答案,此程式應用陣列處理
亦排除了原先執行速度遲緩的困擾,謝謝你的幫忙!

TOP

回復 31# c_c_lai

昨天是用儲存格方式處理,大致需要3分鐘,早上改為陣列處理約需要10秒鐘,再進行優化可達2~3秒鐘
可見儲存格與陣列處理速度相差20倍以上
{...} 表示需要用 CTRL+SHIFT+ENTER 三鍵輸入公式

TOP

回復 32# ML089
試試經修改後之程式:

面積大小分佈統計_ML089.rar (150.15 KB)

TOP

回復 32# ML089
更正圖片,上頭的是在 Debug Mode, 所以時間較長,
更正後之圖片為確實執行秒數。

TOP

本帖最後由 c_c_lai 於 2013-12-7 20:51 編輯

回復 32# ML089
增修後之程式碼如下:
  1. Option Explicit

  2. '  ML089 寫於 2013/12/7
  3. '  http://forum.twbts.com/viewthread.php?tid=10927&extra=&page=3
  4. Sub 連續0個數之統計()
  5.     Dim dic As Object
  6.     Dim t1 As Date, tt1 As Date, t2 As Date, tt2 As Date
  7.     Dim Arr As Variant, xDebug As String, sRng As Range, WriteToRange As Range
  8.     Dim i As Integer, c As Long, r As Long, y As Integer, rN As Long, cN As Long
  9.     Dim Bins_array As Variant, ArrF As Variant, ArrN As Variant, MaxN As Double
  10.    
  11.     Application.Calculation = xlManual    '  關閉計算
  12.     Application.ScreenUpdating = False    '  關閉顯示

  13.     xDebug = InputBox("陣列計算資料寫出。填入 1 / 0 控制 :", "DeBug", 0) '  ◎陣列計算資料寫出。填入 1、Ture / 0、Flase 控制
  14.     If xDebug Then ActiveSheet.Copy after:=ActiveSheet    '  Test Use 1

  15.     t1 = Timer: tt1 = Time    '  秒數計時器
  16.     Set dic = CreateObject("Scripting.Dictionary")
  17.     dic("連續位址") = "組合數量"

  18.     '  ↓ 找 0,將每組連續 0 編不同序號
  19.     '  Arr : Variant/Variant(1 to 20, 1 to 26)
  20.     Arr = ActiveSheet.[A1].CurrentRegion    '  讀入陣列
  21.    
  22.     i = 0
  23.     rN = UBound(Arr, 1)     '  Y  Rows     20
  24.     cN = UBound(Arr, 2)     '  X  Columns  26
  25.    
  26.     For c = 1 To cN
  27.         For r = 1 To rN     '  此迴圈將陣列非0值改為文字型態
  28.             If Arr(r, c) <> 0 Then Arr(r, c) = "X" '  Empty 會被視為 0,"" 不會
  29.         Next
  30.     Next
  31.     For c = 1 To cN
  32.         For r = 1 To rN    '  此迴圈找 0
  33.             If Arr(r, c) = 0 Then
  34.                 i = i + 1
  35.                 Set sRng = Sheets("TEST2").Cells(r, c)
  36.                 Call xRep(Arr, r, c, i, sRng)
  37.                 dic(sRng.Address) = Range(sRng.Address).Count
  38.             End If
  39.         Next
  40.     Next

  41.     If xDebug Then [A1].Resize(rN, cN) = Arr    '  Test Use 2    ' i = 11

  42.     '  ↓ 計算每組個數。 注意! Frequency 回傳 i + 1 組,所先將 i - 1
  43.     Bins_array = Application.Evaluate("Row(1:" & i - 1 & ")")   ' i = 11
  44.     '  計算某一個範圍內的值出現的次數,並傳回一個垂直數值陣列。
  45.     '  例如,用 FREQUENCY 來計算某些範圍內的考試成績各有幾個人。
  46.     '  由於 FREQUENCY 傳回陣列,因此必須輸入為陣列公式。
  47.     ArrN = Application.Frequency(Arr, Bins_array)
  48.     MaxN = Application.Max(ArrN)   '  MaxN : 62 : Variant/Double  (以上統計數的最大值)

  49.     '  ↓ 統計每組個數。 注意! Frequency 回傳 i + 1 組,所先將 MaxN - 1
  50.     Bins_array = Application.Evaluate("Row(1:" & MaxN - 1 & ")")
  51.     ArrF = Application.Frequency(ArrN, Bins_array)

  52.     '  ↓ 寫出資料
  53.     Set WriteToRange = ActiveSheet.Cells(rN + 3, 1)
  54.     WriteToRange.CurrentRegion.ClearContents
  55.     Application.Goto Reference:=WriteToRange, scroll:=True   ' 將畫面切換至 WriteToRange。
  56.     With WriteToRange
  57.         .Resize([A:A].Rows.Count - rN - 3, 2) = ""
  58.         .Resize(1, 2) = Application.Evaluate("{""連續數"", "";組數""}")
  59.         y = 0
  60.         For i = 1 To MaxN
  61.             If ArrF(i, 1) <> 0 Then
  62.                 y = y + 1
  63.                 .Offset(y, 0) = i
  64.                 .Offset(y, 1) = ArrF(i, 1)
  65.             End If
  66.         Next
  67.         .Offset(0, 2).Resize(dic.Count, 1) = Application.Transpose(dic.keys)
  68.         .Offset(0, 3).Resize(dic.Count, 1) = Application.Transpose(dic.items)
  69.          
  70.         t2 = Timer: .Offset(y + 1, 1) = Format(t2 - t1, "0.00") & " 秒"
  71.         tt2 = Time: .Offset(y + 2, 1) = Format((tt2 - tt1) * 24 * 60 * 60, "0.00") & " 秒"
  72.     End With
  73.     Set Arr = Nothing       '  釋放記憶體
  74.     Set dic = Nothing
  75.    
  76.     Application.ScreenUpdating = True
  77.     Application.Calculation = xlCalculationAutomatic
  78. End Sub

  79. '  遞迴呼叫( recursive call )查詢,將連續0寫入同一編號
  80. Sub xRep(ByRef Arr, r, c, i, ByRef rng As Range)
  81.     Dim Temp As Range
  82.    
  83.     Arr(r, c) = i    '  寫入編號
  84.     Cells(r, c).Interior.ColorIndex = 6    '  Test Use 3
  85.     Set Temp = Union(rng, Sheets("TEST2").Cells(r, c))
  86.     On Error Resume Next    '  避免邊界錯誤
  87.     If Arr(r - 1, c) = 0 Then Call xRep(Arr, r - 1, c, i, Temp)    '  找上
  88.     If Arr(r + 1, c) = 0 Then Call xRep(Arr, r + 1, c, i, Temp)    '  找下
  89.     If Arr(r, c - 1) = 0 Then Call xRep(Arr, r, c - 1, i, Temp)    '  找左
  90.     If Arr(r, c + 1) = 0 Then Call xRep(Arr, r, c + 1, i, Temp)    '  找右
  91.     Set rng = Temp
  92. End Sub
複製代碼

TOP

        靜思自在 : 生氣,就是拿別人的過錯來懲罰自己。
返回列表 上一主題