2

我需要从几个工作表中计算某个范围的平均值(“C2:C11”)到一个新的工作表中。如果添加了新工作表并将数据输入到指定范围,该功能应该仍然有效。

到目前为止我有这个

……

Sheets.Add

Dim myavg As Collection
Set myavg = New Collection

For Each wsheet In Worksheets
   myavg.Add wsheet.Range("B2:B11")
Next    
For i = 1 To myavg.Count
   avg1 = Application.WorksheetFunction.Average(Range("B2:B11"))
Next

curColumn = 5
curRow = 4

For i = 1 To myavg.Count
   ActiveSheet.Cells(curRow, curColumn).Value = avg1
   curRow = curRow + 1
Next  

...

它将一个数字返回到新工作表的所需范围内,并且不准确

请帮助我理解我做错了什么。先感谢您。

4

1 回答 1

2

先不管 a 是否Collection适合这个任务,让我们检查一下你的代码:

一般
您可能已经这样做了,但它警告重复
使用Option Explicit并标记所有变量

你的代码

Sheets.Add

Worksheet这会在 active中添加一个新的Workbook,并将其放在当前活动的工作表之前,然后激活新工作表。
问题: 您依靠默认行为来获取新的Worksheet,您无法确定新工作表的位置,并且您没有参考它。
建议:
获取对工作簿对象的引用并在整个代码中使用它

Dim wb As Workbook
Set wb = ActiveWorkbook

控制添加到工作簿的内容、位置和方式

Dim wsSummary as Worksheet
Set wsSummary = wb.Worksheets.Add(After:=wb.Worksheets(wb.Worksheets.Count))
wsSummary.Name = "Summary"

你的代码

For Each wsheet In Worksheets
    myavg.Add wsheet.Range("B2:B11")
Next  

这会从书中的每个内容中创建一个Collectionof ,包括我们刚刚创建的那个。我猜你不想包括那个。为了便于维护,您应该创建一个变量来保存范围并在整个代码中使用它。让我们应用上述内容RangeWorksheet

Dim wsheet as WorkSheet
Dim RangeAddress As String
RangeAddress = "B2:B11"
For Each wsheet In wb.Worksheets
    If wsheet.name <> wsSummary.Name Then
        myavg.Add wsheet.Range(RangeAddress)
    End If
Next  

你的代码

For i = 1 To myavg.Count
    avg1 = Application.WorksheetFunction.Average(Range("B2:B11"))
Next

问题: 您正在迭代Collection但没有在循环中引用它。每次通过您计算avg1,然后在下一个循环中覆盖它。
每次通过循环时,您都会计算活动工作表上某个范围的平均值(这将是刚刚添加的空白新 工作

)连续的行。因此,让我们将平均值存储在一个数组中,以便稍后放在汇总表上。请注意,如果任何一个Range为空,Average将导致错误。

Dim avg() as Variant
Redim avg(1 to myavg.Count, 1 To 1)
For i = 1 To myavg.Count
    avg(i, 1) = Application.WorksheetFunction.Average(myavg(i))
Next

你的代码

curColumn = 5
curRow = 4

For i = 1 To myavg.Count
    ActiveSheet.Cells(curRow, curColumn).Value = avg1
    curRow = curRow + 1
Next

问题:
此代码只是将最后计算的值avg1放在连续的行上

将结果放到新工作表上:将平均值收集到一个数组中,让我们把它放到工作表上

Dim curColumn as Long, curRow As Long
curColumn = 5
curRow = 4

wsSummary.Cells(curRow, curColumn).Resize(UBound(avg, 1), 1) = avg

到目前为止,没有被删除的是Error Handling. 代码出错的方式有很多种,因此将其包含Error Handling在代码中是明智之举。例如,如果已经有一个名为“摘要”的工作表怎么办?如果Average返回错误怎么办?


谈到这是否是一个好方法,应该清楚的是,在创建了一个数组来保存结果之后,可以在工作簿的传递中填充该数组。

像这样的东西

Sub Demo()
    Dim wb As Workbook
    Set wb = ActiveWorkbook

    Dim RangeAddress As String
    RangeAddress = "B2:B11"

    Dim wsSummary As Worksheet

    Dim avg() As Variant
    ReDim avg(1 To wb.Worksheets.Count, 1 To 1)
    For i = 1 To UBound(avg, 1)
        With wb.Worksheets(i).Range(RangeAddress)
            If WorksheetFunction.Count(.Value) > 0 Then
                avg(i, 1) = WorksheetFunction.Average(.Value)
            Else
                avg(i, 1) = "No Values On Sheet"
            End If
        End With
    Next

    Dim curColumn As Long, curRow As Long
    curColumn = 5
    curRow = 4

    On Error Resume Next
    Set wsSummary = wb.Worksheets("Summary")
    If Err.Number <> 0 Then
        ' Summary sheet does not exist, create it
        Err.Clear
        On Error GoTo 0
        Set wsSummary = wb.Worksheets.Add(After:=wb.Worksheets(wb.Worksheets.Count))
        wsSummary.Name = "Summary"
    Else
        On Error GoTo 0
        ' Summary sheet already exists
        ' what do you wnat to do?
    End If

    wsSummary.Cells(curRow, curColumn).Resize(UBound(avg, 1), 1) = avg

End Sub

此代码可能仍然存在问题,具体取决于您的确切要求(例如,如果“摘要”表已经存在,这将在平均循环中处理它)

于 2012-10-21T23:27:33.240 回答