Home > Blockchain >  How to apply formula to each cell in column vba range?
How to apply formula to each cell in column vba range?

Time:04-29

I have an excel file with a column full of numbers (occasionally there will be some text or a blank cell) for example

4
5
10
13
5

4
not applicable

9
2
1
6

I want to apply a function to that cell that does the following. If the cell value is blank or text do nothing. If the value is less that 8 then make it 8, if it is greater than or equal to 8 do nothing. So my example column would become:

8
8
10
13
8

8
not applicable

9
8
8
8

I wish to overwrite the values in the cell with the new values as opposed to preserving the original values that were in the cell.

Of course I could do =max(cell, 8) and then just copy the output down the column and the copy/paste values over the top of the column but I need to do this for multiple columns on a sheet (100's of times) so I need a good way to do this.

So far I have managed to write a macro that iterates through my sheet and selects the columns I need to update but I don't know how to actually update them.

Can I define a function and then apply it to each cell in a column? Is there a faster/more efficient way to do this.

EDIT

Code so far:

Sub updatemin()

Dim i, updatecol As Integer
updatecol = 14


For i = 1 To 100
    Columns(updatecol).Select
    'need to figure out how to make any values less than 8 into 8 for the cells in the given range before moving on to the next column to do the same.
    updatecol = updatecol   22
Next i

End Sub

CodePudding user response:

Update Columns

Option Explicit

Sub UpdateMin()

    Const FirstCellAddress As String = "N2"
    Const ColumnOffset As Long = 22
    Const ColumnsCount As Long = 100
    Const MinCriteria As Double = 8
    
    Dim ws As Worksheet: Set ws = ActiveSheet ' improve!
    
    Dim fCell As Range: Set fCell = ws.Range(FirstCellAddress)
    
    Dim rg As Range
    Dim lCell As Range
    Dim rCount As Long
    
    With fCell.Resize(ws.Rows.Count - fCell.Row   1, _
            (ColumnsCount - 1) * ColumnOffset   1)
        Set lCell = .Find("*", , xlFormulas, , , xlPrevious)
        If lCell Is Nothing Then Exit Sub
        rCount = lCell.Row - .Row   1
        Set rg = .Resize(rCount, 1)
    End With
    
    Dim Data As Variant
    Dim cValue As Variant
    Dim r As Long
    Dim c As Long
    
    For c = 1 To ColumnsCount
        With rg.Offset(, (c - 1) * ColumnOffset)
            'Debug.Print .Address
            Data = .Value
            For r = 1 To rCount
                cValue = Data(r, 1)
                If VarType(Data(r, 1)) = vbDouble Then
                    If cValue < MinCriteria Then
                        Data(r, 1) = MinCriteria
                    End If
                End If
            Next r
            .Value = Data
            '.Interior.Color = vbYellow
        End With
    Next c
    
    MsgBox "Columns updated.", vbInformation

End Sub

CodePudding user response:

Imagine the following data in column A

enter image description here

Use the following code to loop through all data and if it is smaller then 8 turn it into 8, omit the cells if they're not numeric or if they are empty.

Option Explicit

Public Sub Example()
    Dim ws As Worksheet  ' define your worksheet
    Set ws = ThisWorkbook.Worksheets("Sheet1")

    Dim LastRow As Long  ' find last used row in column A
    LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row

    ' update data to MinValue in the given DataRange
    UpdateValuesToMinimum MinValue:=8, DataRange:=ws.Range("A1", "A" & LastRow)
End Sub


Public Sub UpdateValuesToMinimum(ByVal MinValue As Long, ByVal DataRange As Range)
    Dim DataValues() As Variant  ' read all data into an array for faster processing
    DataValues = DataRange.Value2
    
    Dim iRow As Long  ' loop through all rows
    For iRow = LBound(DataValues, 1) To UBound(DataValues, 1)
        Dim iCol As Long  ' loop through all columns
        For iCol = LBound(DataValues, 2) To UBound(DataValues, 2)
            ' check if it is numeric and not empty
            If IsNumeric(DataValues(iRow, iCol)) And DataValues(iRow, iCol) <> vbNullString Then
                ' if data is <MinValue set it to MinValue 
                If DataValues(iRow, iCol) < MinValue Then
                    DataValues(iRow, iCol) = MinValue
                End If
            End If
        Next iCol
    Next iRow
    
    ' write array data back to the cells
    DataRange.Value2 = DataValues
End Sub

And you will get as result:

enter image description here

CodePudding user response:

I propose to separate obtaining and processing of data. As for the latter, why not to apply a formula =IF(Data < Minimum, Minimum, Data) to numbers in a data range? To select only numbers, we can use SpecialCells.

Sub UpdateMin(Data As Range, Optional MinCriteria As Double)
Dim Numbers As Range
Dim Area As Range
Dim Formula As String
    On Error Resume Next
    Set Numbers = Data.SpecialCells(xlCellTypeConstants, xlNumbers)
    If Numbers Is Nothing Then Exit Sub
    On Error GoTo 0
    For Each Area In Numbers.Areas
        ' =IF(Area < MinCriteria, MinCriteria, Area)
        Formula = "IF(" & Area.Address & "<" & MinCriteria & "," & MinCriteria & "," & Area.Address & ")"
        Area.Value2 = Evaluate(Formula)
    Next Area
End Sub

We need to iterate over continuous areas here to calculate IF(...) as an array formula. To get the range of interest in your case I'd use this code:

Function getData() As Range
Dim Result As Range
Const DataSheet = "Sheet1"
Const first = 14
Const delta = 22
Const last = first   99 * delta
Dim i&
    ' rebuild to your needs
    With ThisWorkbook.Worksheets(DataSheet)
        Set Result = .Columns(first)
        For i = first   delta To last Step delta
            Set Result = Union(Result, .Columns(i))
        Next i
        Set getData = Intersect(Result, .UsedRange)
    End With
End Function
 

The final part:

Sub main_macro()
    UpdateMin getData, 8
End Sub

I'm not sure if this is a good approach, because we are iterating over data twice - to select numbers and then to update them. But both parts are addressed to Excel itself. So the job, I hope, is gonna be done quickly at least in case of big chunks of numbers. The worst scenario, I think, is a regular alternation of numbers and words. Let me know about your choice and how it worked in the end.

  • Related