返回列表 上一主題 發帖

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

回復 13# Hsieh
回復 16# ML089
回復 11# stillfish00
面積大小分佈統計B.rar (108.71 KB)
感謝各位的幫忙,如還有更佳效益的解決方案,
敬請不吝指教!

TOP

本帖最後由 c_c_lai 於 2013-12-7 08:05 編輯

回復 16# ML089
以常理來論, 10 與 25 應無彼此間之串聯,應屬不同之區塊才是,
你在實作上是如何解析的?

TOP

回復 16# ML089
Hsieh 版大他是應用 "遞迴" 的處理技巧,來求出各歸屬區塊的範圍,
這種點及於面的運用是個蠻不錯的 Idea,你看看程式碼細細地去推敲,
是蠻值得回味的, 在�媕Y我加上了 sRng 的位址紀錄處理,並同時求取
每個區塊的實際位址數,以提供參考之用:
  1. Option Explicit

  2. Public s As Long
  3. Public sRng As Variant

  4. Sub ex()
  5.     Dim dic As Object
  6.     Dim A As Range, Rng As Range, sPos As Range
  7.    
  8.     Set dic = CreateObject("Scripting.Dictionary")
  9.     dic("連續數量") = "數量"
  10.     '   增列部分
  11.     工作表2.[C1] = "連續位址"
  12.     工作表2.[D1] = "組合數量"
  13.    
  14.     With 工作表1
  15.         Set Rng = .Range("A1").CurrentRegion
  16.         Rng.Replace 0, Empty, xlWhole
  17.         
  18.         Set sPos = 工作表2.[C2]
  19.         Set A = Rng.Find(Empty)
  20.         
  21.         Do Until A Is Nothing
  22.             A = 0: s = 1
  23.             Cnt A
  24.             dic(s) = dic(s) + 1
  25.             
  26.             sPos = sRng
  27.             sPos.Offset(0, 1) = Range(sRng).Count
  28.             
  29.             Set A = Rng.Find(Empty)
  30.             
  31.             Set sPos = sPos.Offset(1)
  32.         Loop
  33.     End With
  34.    
  35.     With 工作表2
  36.         .[A1].Resize(dic.Count, 1) = Application.Transpose(dic.keys)
  37.         .[B1].Resize(dic.Count, 1) = Application.Transpose(dic.items)
  38.         .[A1].Resize(dic.Count, 2).Sort key1:=.[A1], Header:=xlYes
  39.     End With
  40.    
  41.     '  MsgBox dic.Count - 1
  42.     Set dic = Nothing
  43. End Sub

  44. Function Cnt(Rng As Range)
  45.     Dim A As Range, Temp As Range
  46.     Dim i As Integer
  47.         
  48.     For Each A In Rng
  49.         For i = -1 To 1 Step 2
  50.             If A.Row + i > 0 And A.Row + i < 工作表1.Range("A1").CurrentRegion.Rows.Count Then
  51.                 If IsEmpty(A.Offset(i, 0)) Then Set Temp = Union(Rng, A.Offset(i, 0))   '  "$BF$4:$BF$5"
  52.             End If
  53.         Next
  54.         For i = -1 To 1 Step 2
  55.             If A.Column + i > 0 And A.Column + i < 工作表1.Range("A1").CurrentRegion.Columns.Count Then
  56.                 If IsEmpty(A.Offset(, i)) Then Set Temp = Union(Rng, A.Offset(, i))   '  "$BF$4:$BG$4"
  57.             End If
  58.         Next
  59.     Next

  60.     If Not Temp Is Nothing Then      '  True
  61.         Temp = 0
  62.         s = Temp.Count
  63.         sRng = Temp.Address
  64.         Cnt Temp
  65.     End If
  66. End Function
複製代碼

TOP

本帖最後由 c_c_lai 於 2013-12-7 08:42 編輯

回復 20# c_c_lai
20# 的 Ex() 內之 C、D 欄一行一行地去遞增是為了要
觀察資料處理及過程。以下為改以 "字典" 處裡:
  1. Sub ex2()
  2.     Dim dic As Object, dic2 As Object
  3.     Dim A As Range, Rng As Range
  4.    
  5.     Set dic = CreateObject("Scripting.Dictionary")
  6.     Set dic2 = CreateObject("Scripting.Dictionary")
  7.     dic("連續數量") = "數量"
  8.     dic2("連續位址") = "組合數量"
  9.    
  10.     With 工作表1
  11.         Set Rng = .Range("A1").CurrentRegion
  12.         Rng.Replace 0, Empty, xlWhole
  13.         
  14.         Set A = Rng.Find(Empty)
  15.         
  16.         Do Until A Is Nothing
  17.             A = 0: s = 1
  18.             Cnt A
  19.             dic(s) = dic(s) + 1
  20.             dic2(sRng) = Range(sRng).Count
  21.             
  22.             Set A = Rng.Find(Empty)
  23.         Loop
  24.     End With
  25.    
  26.     With 工作表2
  27.         .[A1].Resize(dic.Count, 1) = Application.Transpose(dic.keys)
  28.         .[B1].Resize(dic.Count, 1) = Application.Transpose(dic.items)
  29.         .[A1].Resize(dic.Count, 2).Sort key1:=.[A1], Header:=xlYes
  30.         .[C1].Resize(dic2.Count, 1) = Application.Transpose(dic2.keys)
  31.         .[D1].Resize(dic2.Count, 1) = Application.Transpose(dic2.items)
  32.    End With
  33.    
  34.     '  MsgBox dic.Count - 1
  35.     Set dic = Nothing
  36.     Set dic2 = Nothing
  37. End Sub
複製代碼
感謝 Hsieh 版大的指導!

TOP

回復 23# ML089
請教:
  1.     '  ↓ 計算每組個數。 注意! Frequency 回傳 i + 1 組,所先將 i - 1
  2.     Bins_array = Application.Evaluate("Row(1:" & i - 1 & ")")
  3.     ArrN = Application.Frequency(Arr, Bins_array)
  4.     MaxN = Application.Max(ArrN)

  5.     '  ↓ 統計每組個數。 注意! Frequency 回傳 i + 1 組,所先將 MaxN - 1
  6.     Bins_array = Application.Evaluate("Row(1:" & MaxN - 1 & ")")
  7.     ArrF = Application.Frequency(ArrN, Bins_array)
複製代碼
Bins_array、ArrN 、MaxN 、ArrF  的內涵及作用,能否加以解析,
我對一些用語不很孰悉,且反應較遲鈍,謝謝囉!

TOP

本帖最後由 c_c_lai 於 2013-12-7 17:22 編輯

回復 26# stillfish00
回復 27# ML089
的確!
提取到Array確實加速很多,同時也解決了遲緩的困擾。
謝謝你等的指教!

TOP

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

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

        靜思自在 : 能付出愛心就是福,能消除煩惱就是慧。
返回列表 上一主題