为一系列单元格

时间:2018-01-18 18:10:11

标签: excel vba excel-vba

这是一个非常基本的问题,我确信它已被回答,但我似乎无法在其他地方找到它。我有一部分vba代码适用于单个单元格。但是我想将它扩展为适用于一系列单元格(所有单元格都在同一列中)。

基本上它的目标寻找循环改变了“b”列中的值,直到“w”列中的值与“x”列中的值匹配(在99%以内)。

什么有效:

Sub Goalseeker()

Do Until Range("w32").Value / Range("x32").Value > 0.99
    Range("b32").Value = Range("b32").Value - 1
Loop

End Sub

我想将其扩展为第32行到第107行。 我尝试过的: 编辑:我根据收到的评论进行了调整,并在工作之前做了一些调整。如果有人对这个过程感兴趣:

Option Explicit

Sub Goalseeker()

Dim i As Integer
Dim targetcell As Double
Dim outputcell As Double
Dim variablecell As Range

For i = 32 To 107

targetcell = Cells(i, "x")
outputcell = Cells(i, "w")
Set variablecell = Range("B" & i)

Do Until outputcell / targetcell > 0.99
    variablecell = variablecell - 1
    targetcell = Cells(i, "x")
    outputcell = Cells(i, "w")
Loop

Next

End Sub

我不得不调整的是

Do Until outputcell / targetcell > 0.99
    variablecell = variablecell - 1
    targetcell = Cells(i, "x")
    outputcell = Cells(i, "w")
Loop

重新定义(我道歉,如果这是错误的术语)targetcell和outputcell是必要的,以防止无限循环。

谢谢大家。我将努力为相对引用而不是绝对引用此函数。

2 个答案:

答案 0 :(得分:0)

这里几乎没有问题。将For i循环更改为格式For i = x to y而非For i = x to i = y

您可以将targetcelloutputcell称为double,但variablecell必须是range。如果它是range则需要Set

您应该声明所有变量,如下所示。

最后,您可能希望放入一个捕捉以摆脱无限循环(如果目标永远不会达到0.99以上?)

Sub Goalseeker()

Dim i As Integer

Dim targetcell As Double
Dim outputcell As Double
Dim variablecell As Range

For i = 32 To 107

    targetcell = Cells(i, "x")
    outputcell = Cells(i, "w")
Set variablecell = Range("B" & i)

    Do Until outputcell / targetcell > 0.99
        variablecell = variablecell - 1
    Loop

Next

End Sub

答案 1 :(得分:0)

考虑以下示例表:

table

使用以下代码在" B"中找到正确的值。列(如图所示),以便最小化结果(下一列)和目标(两列以上)之间的误差。

Option Explicit

Public Sub GoalSeekMyValues()

    ' Call GoalSeek with inputvalues "B2:B16", having the result
    ' at column offset 1, and the goal in column offset 2.
    ' Note that Range("B2").Resize(15, 1) = Range("B2:B16"),
    ' But I prefer the top cell and row count of this syntax.
    GoalSeek Range("B2").Resize(15, 1), 1, 2

End Sub

Public Sub GoalSeek(ByVal variables As Range, ByVal result_offset As Long, ByVal goal_offset As Long)
    Dim n As Long, i As Long, pct_error As Double, last_error As Double
    'x is the input value (variable)
    'y is the result
    'g is the goal for y
    Dim x As Double, y As Double, g As Double
    ' Read the number of rows in the input values
    n = variables.Rows.Count
    Dim r As Range
    ' Loop through the rows
    For i = 1 To n
        'Set a range reference at the i-th input cell
        Set r = variables.Cells(i, 1)
        ' Read the value, the result and the goal
        x = r.Value
        y = r.Offset(0, result_offset).Value
        g = r.Offset(0, goal_offset).Value
        pct_error = Abs(y / g - 1)
        Do
            'Set the next value
            r.Value = x - 1
            ' Read the result (assume goal doesn't change)
            y = r.Offset(0, result_offset).Value
            ' Keep last error, and calculate new one
            last_error = pct_error
            pct_error = Abs(y / g - 1)
            ' If new error is more than last then exit the loop
            ' and keep the previous value (with less error).
            If pct_error > last_error Then
                ' Keep last value
                r.Value = x
                Exit Do
            End If
            ' read the input value
            x = r.Value
            ' Assume inputs must be positive so end the loop
            ' on zero on negative numbers
        Loop Until x <= 0
    Next i
End Sub

您的代码有很多失败点

  1. 您的代码可能无法达到解决方案并且excel将挂起(直到按下 Ctrl - Break )。当输入变为零或负数时,我会有一个艰难的休息时间。其他问题需要其他方法来告诉我们没有解决方案。
  2. 第一次结果在解决方案的1%范围内可能不会产生最少的错误。我通过跟踪相对误差的绝对值来解决这个问题。只有当错误开始增加时,我才会终止循环。这假设将输入减少一个单位将改善解决方案(至少最初)。如果不是这种情况,则代码将失败。
  3. 您使用绝对引用(如读取第12个单元格和第4个单元格),这不是非常可重复使用的编程风格。我总是尝试使用相对引用。我从左上角引用的单元格(在本例中为B2)开始,并使用以下方法从那里向下移动:

    • Range("B2").Cells(5,1) - 参考B2的第5行和第1列。
    • Range("B2").Resize(15, 1) - 展开范围以包含15行和1列。
    • Range("B2).Cells(i,1).Offset(0, 3) - 从i - 行使用列偏移量3(表示表格中的第4列)。
  4. 我建议使用一种常见的目标寻求方法(如二分),或者更好的是,使用内置的目标搜索功能

  5. 示例:

    Range("B2").Cells(i,2).GoalSeek Goal:=Range("B2").Cells(i,3).Value, ChangingCell:=Range("B2").Cells(i,1)