2017-08-14 26 views
2

這對我來說是一個棘手的問題,所以我將從我到目前爲止的代碼開始,然後再以我嘗試實現的代碼開始。如何計算自定義類型數組的1個變量的平均值

Option Explicit 

Public eSigTickerArr As Variant 

' Public type to save array 
Type Watchlist 
    eSigTicker As String 
    Op As Double 
    Hi As Double 
    Lo As Double 
    Cl As Double 
    Vol As Double 
    BarTime As Variant 
End Type 
Public WatchlistArr() As Watchlist ' save an array of special type "Watchlist" 

'==================================================================== 

Sub Mainr() 

ReDim WatchlistArr(0) ' init array size 
eSigTickerArr = Array("Part1", "Part2", "Part3") 

For Each eSigTickerElem In eSigTickerArr 

    ' check if first member of array is occupied 
    If WatchlistArr(0).eSigTicker <> "" Then ' not first time running this code >> increase array size by 1 
     ReDim Preserve WatchlistArr(UBound(WatchlistArr) + 1) ' increase array size by 1 
    End If 

    ' ... Some Code, working fine .... 

    ' populate array Type with data (also works) 
    With WatchlistArr(UBound(WatchlistArr)) 
     .eSigTicker = eSigTickerElem 
     .Op = LastCSVLine(2) 
     .Hi = LastCSVLine(3) 
     .Lo = LastCSVLine(4) 
     .Cl = LastCSVLine(5) 
     .Vol = LastCSVLine(6) 
     .BarTime = LastCSVLine(1) 
    End With 

Next eSigTickerElem 

' ******* calculate the average of only "Hi" ****** 
Dim myAvg 

myAvg = WorksheetFunction.Average(WatchlistArr.Hi) '<--- Getting an Error ! 

End Sub 

我在該行收到錯誤高於目前的代碼。

我的挑戰:我想要得到的平均只有我喜歡的類型數組WatchlistArr的某個變量的,我不希望使用一個循環,因爲可以有10000條記錄(或更多)。

有沒有辦法用Average函數獲取數值?

我應該切換到二維數組嗎?或者也許3-D數組?

+0

爲什麼你不想使用循環?它們非常快,甚至有數以萬計的迭代。 – Graham

+1

'平均'可能如何實施?哦,沒錯!一個循環! –

回答

1
myAvg = WorksheetFunction.Average(WatchlistArr.Hi) '<--- Getting an Error ! 

是的。這段代碼意味着做的是與此類似:

myAvg = watchListArr.Select(item => item.Hi).Average(); 

哪裏item => item.Hi是在watchListArr調用爲每個項目選擇功能。唯一的問題是,這是LINQ/C#,而不是VBA。 VBA不支持委託和其他時髦的東西,即使C#在v1.0中也無法實現。

但VBA 有讓你在一個陣列執行的操作爲每個項目控制流結構:使用For循環!

Dim i As Long, total As Double, count As Long 
For i = LBound(watchListArr) To UBound(watchListArr) 
    total = total + watchListArr(i).Hi 
    If watchListArr(i).Hi <> 0 Then count = count + 1 'assuming zeroes are excluded 
Next i 
If count <> 0 Then myAvg = total/count 

如果你想使用Application.WorksheetFunction.Average,你需要每一個項目的Hi成員陣列中拷貝到自己的數組,並給它陣列 - 這將需要一個...循環...這是浪費週期如果該循環不是計算它的平均值。

只要你沒有使用For Each循環迭代數組,你將會很好。使用For循環迭代30K物品陣列幾乎是瞬間的,不用擔心。

+0

謝謝,需要多少時間來循環約30,000條記錄?我在辯論如果切換到2D陣列?我甚至可能必須去3D數組才能逃脫循環。我的問題是值得的嗎? –

+0

@ShaiRado以及我剛剛寫了一個快速測試,其中一次迭代填充30K項目,另一個計算每個30K項目中UDT的一個元素的總和,並且兩個循環立即完成。在性能成爲實際問題之前,我不會擔心性能。有沒有聽說過「不成熟的優化」?順便說一句'WorksheetFunction.Average'是** NOT **消除循環,它只是將它從* your *代碼中抽象出來。 –

+0

你仍然是第一! –

1

可以定義WatchlistArr作爲2 d數組,然後嘗試這個邏輯:

Dim myArray As Variant 
myArray = Application.WorksheetFunction.Index(WatchlistArr, 0, 2) 

這將返回塔2爲作爲陣列,其可以被傳遞到平均方法:

myAvg = WorksheetFunction.Average(myArray)