Home > Back-end >  Use result value of a do while loop as input value for next loop vba excel
Use result value of a do while loop as input value for next loop vba excel

Time:08-17

I'm new to vba and I'm having trouble writing in my code that each loop, should use as input the value of the previous loop.

Specifically, in the table below , what I want to achieve is get the result of X = E5 - F5, then do X - G5 and so on until column W. Below my code as well

I'm sure the answer is quite simple but I cannot wrap my head around it. Thank you in advance!

enter image description here

r = 5
c = 6

Dim UseV As Long
Dim StartV As Long
Dim EndV2 As Long
Dim EndV As Long


Do While r <= LastFCrow2 'loop through all rows
    
    If FCws.Cells(r, 2).Value <> PrevYM And FCws.Cells(r, 4).Value <> 0 And FCws.Cells(r, 3).Value = "PldOrd" Then 'only test rows of the new dataset, where contract exists, only for forecasted qty
    
    StartV = FCws.Cells(r, 5).Value
    
      Do While c <= LastFCcol 'loop through all columns: all values in one row
                    
            
            UseV = FCws.Cells(r, c).Value
            EndV = StartV - UseV 'can't store somewhere the EndV so that it will be used as the startV in the next iteration
           
          
            If EndV > 0 Then  'go to next month,format top and bottom line
                With FCws.Cells(r, c) _
                    .Borders(xlEdgeTop)
                        .LineStyle = xlContinuous
                        .ColorIndex = xlAutomatic
                        .TintAndShade = 0
                        .Weight = xlThin
                End With
            End If
            
            If EndV < 0 Then  ' run out during month, format diagonal line
                With FCws.Cells(r, c) _
                    .Borders(xlDiagonalDown)
                        .LineStyle = xlContinuous
                        .ColorIndex = xlAutomatic
                        .TintAndShade = 0
                        .Weight = xlThin
                End With
             Exit Do  'loop will exit to next r aftet the current r,c combination that first satisfies the EndV<0 outcome
            End If
            
             If EndV = 0 Then  ' run out after month, format top and right side border
               With FCws.Cells(r, c) _
                    .Borders(xlEdgeRight)
                        .LineStyle = xlContinuous
                        .ColorIndex = xlAutomatic
                        .TintAndShade = 0
                        .Weight = xlThin
                End With
                With FCws.Cells(r, c) _
                    .Borders(xlEdgeTop)
                        .LineStyle = xlContinuous
                        .ColorIndex = xlAutomatic
                        .TintAndShade = 0
                        .Weight = xlThin
               End With
               Exit Do 'loop will exit to next r aftet the current r,c combination that first satisfies the EndV=0 outcome
            End If

            
        c = c   1
        Loop
        c = 6
       End If
    r = r   4
    Loop

CodePudding user response:

Something like this maybe?

c = 4
X = Cells(5, c).Value - Cells(5, c   1).Value
LastFCcol = 10

Do While c <= LastFCcol
    'Do something with X here
    X = X - Cells(5, c   1).Value
    c = c   1
Loop

CodePudding user response:

Here is a longer answer, with some guidance on how to clearly use the code itself to describe what you're doing.

  1. Use constants for "magic numbers", such as columns for specific data. Someone looking at your code will see a "2" and won't automatically relate that to the dataset value.
  2. Declare ALL your variables and use Option Explicit
  3. Find any common code - in your case, it's setting the cell borders - and use it in a common function or sub.

One thing I believe may be an issue is storing the lastQty value because it should be associated with a specific dataset. Your data may be well-ordered and will ALWAYS have dataset lines right next to each other. Using the Collection may be overkill in this case, but I'm hoping it shows another way to access the previous quantity.

Option Explicit

Sub FormatQuantities()
    Dim fcWS As Worksheet
    Set fcWS = ThisWorkbook.Sheets("FC")
    With fcWS
        Dim lastRow As Long
        Dim lastCol As Long
        lastRow = .Cells(.Rows.Count, 1).End(xlUp).row
        lastCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
        
        Const FIRST_ROW As Long = 5    'why is this 5 and not 2 ?
        Const FIRST_COL As Long = 6
        Const DATASET_COL As Long = 2
        Const MRP_ELEM_COL As Long = 3
        Const CONTRACTS_COL As Long = 4
        Const OPEN_QTY_COL As Long = 5
        
        Dim lastQty As Collection
        Set lastQty = New Collection
        
        Dim prevDataset As String
        Dim r As Long
        Dim c As Long
        For r = FIRST_ROW To lastRow
            '--- only test rows of the new dataset, where contract exists,
            '    only for forecasted qty
            If .Cells(r, MRP_ELEM_COL).Value = "PldOrd" Then
                If (.Cells(r, CONTRACTS_COL).Value > 0) And _
                   (.Cells(r, DATASET_COL).Value <> prevDataset) Then
                   
                    '--- set the starting quantity to either zero or the
                    '    previously calculated endQty
                    Dim startQty As Long
                    If CollectionContains(lastQty, .Cells(r, DATASET_COL).Value) Then
                        startQty = lastQty(.Cells(r, DATASET_COL).Value)
                    Else
                        startQty = .Cells(r, OPEN_QTY_COL).Value
                    End If
                    
                    '--- format the cell based on the relative quantity
                    For c = FIRST_COL To lastCol
                        Dim usedQty As Long
                        Dim endQty As Long
                        endQty = startQty - .Cells(r, c).Value
                        Select Case endQty
                            Case Is < 0
                                FormatCellBorder .Cells(r, c), xlDiagonalDown
                            Case Is = 0
                                FormatCellBorder .Cells(r, c), xlEdgeRight
                                FormatCellBorder .Cells(r, c), xlEdgeTop
                            Case Is > 0
                                FormatCellBorder .Cells(r, c), xlEdgeTop
                        End Select
                    Next c
                    '--- store the ending quantity for this dataset to be
                    '    used the next time we find it
                    lastQty.Add endQty, .Cells(r, DATASET_COL).Value
                End If
            End If
        Next r
    End With
End Sub

Sub FormatCellBorder(ByRef theCell As Range, ByVal index As XlBordersIndex)
    With theCell.Borders(index)
        .LineStyle = xlContinuous
        .ColorIndex = xlAutomatic
        .TintAndShade = 0
        .Weight = xlThin
    End With
End Sub

Function CollectionContains(myCol As Collection, checkVal As Variant) As Boolean
    '--- from: https://analystcave.com/vba-collection/
    On Error Resume Next
    CollectionContains = False
    Dim it As Variant
    For Each it In myCol
        If it = checkVal Then
            CollectionContains = True
            Exit Function
        End If
    Next
End Function
  • Related