Option Explicit
Public Function Vlookup2(ByVal Lookup_Value As String, ByVal Cell_Range As Range, ByVal Column_Index As Integer) As Variant
Dim cell As Range
Dim Result_String As String
On Error GoTo errHandle
For Each cell In Cell_Range
If cell.Value = Lookup_Value Then
If cell.Offset(0, Column_Index - 1).Value <> "" Then
If Not Result_String Like "*" & cell.Offset(0, Column_Index - 1).Value & "*" Then
Result_String = Result_String & ", " & cell.Offset(0, Column_Index - 1).Value
Exit Function
End If
End If
End If
Next cell
Vlookup2 = LTrim(Right(Result_String, Len(Result_String) - 1))
Exit Function
errHandle:
Vlookup2 = ""
End Function
I have the Function Vlookup and it goes through every cell from the top to the bottom, but I want it to go from bottom to top because that'll be faster. I'd be faster because the code will stop at a certain value and odds are that it'll find the value much faster if it starts from below rather than above
I'm answering this so that others, who have this question and come to this post, will have an example even if this isn't suitable or optimal for #Apples.
Sub Example()
'Loops through a range in reverse
'Significantly slower than UsingArrays (see below)
Dim ExampleRange As Range
Set ExampleRange = Sheet1.Range("A1:CA9999")
Dim i As Long, Cell As Range
For i = ExampleRange.Cells.Count To 1 Step -1
Set Cell = ExampleRange.Cells(i)
'Cell now refers to each individual cell within the range in reverse order!
Next i
End Sub
Sub UsingArrays()
'Copies Range to an Array
'Loops through the Array in reverse
Dim ExampleRange As Range
Set ExampleRange = Sheet1.Range("A1:CA9999")
Dim Values As Variant
Values = ExampleRange.Value
If IsArray(Values) Then
Dim i As Long, j As Long, Value As Variant
For i = UBound(Values) To LBound(Values)
For j = UBound(Values, 2) To LBound(Values, 2)
Value = Values(i, j)
'Value now refers to each individual cell's value in reverse order through the array
Next j
Next i
Else
MsgBox "This handles cases where ExampleRange is a single cell."
End If
End Sub
I have a column of Excel cells that follow this format (the random strings are not in a fixed order). Strings that don't start with a certain string need to be removed.
randomstringA text_that_needs_to_be_kept1
text_that_needs_to_be_removed1
randomstringB text_that_needs_to_be_kept2
randomstringA text_that_needs_to_be_kept3
text_that_needs_to_be_removed2
I want the cell's output to be this (linebreak must be kept):
text_that_needs_to_be_kept1
text_that_needs_to_be_kept2
text_that_needs_to_be_kept3
And not this (linebreak got removed):
text_that_needs_to_be_kept1
text_that_needs_to_be_kept2
text_that_needs_to_be_kept3
The following code will go down column A starting in row 1 and remove any line that doesn't start with a value from the array arrToKeep, keeping the linebreaks.
Option Explicit
Sub RemoveStrings()
Dim rngData As Range
Dim arrData As Variant
Dim arrLines As Variant
Dim arrToKeep As Variant
Dim idx1 As Long
Dim idx2 As Long
Dim idxRow As Long
Dim boolKeep As Boolean
arrToKeep = Array("randomstringA", "randomstringB")
Set rngData = Range("A1", Range("A" & Rows.Count).End(xlUp))
arrData = rngData.Value
For idxRow = LBound(arrData, 1) To UBound(arrData, 1)
arrLines = Split(arrData(idxRow, 1), vbLf)
For idx1 = LBound(arrLines) To UBound(arrLines)
boolKeep = False
For idx2 = LBound(arrToKeep) To UBound(arrToKeep)
If arrLines(idx1) Like arrToKeep(idx2) & "*" Then
boolKeep = True
Exit For
End If
Next idx2
If Not boolKeep Then
arrLines(idx1) = ""
End If
Next idx1
arrData(idxRow, 1) = Join(arrLines, vbLf)
Next idxRow
rngData.Value = arrData
End Sub
In B1 place this formula =IF(LEFT(A1;1)="r";MID(A1;FIND(" ";A1;1)+1;500);"") and copy+paste to the other cells in column B.
I have a dataset that is multiple strings and I want a unique count of the occurrences so I can review and refine my datasets. I've been unable to do this using formulas so went over to VBA, but hit a roadblock as I'm an amateur.
My data looks like this...
I want it to return this...
I've tried parsing it with text to columns, but in large datasets I have 60 columns with 100s of hits in my string. Therefore, transposing it then trying to get a count of uniques would be daunting.
Therefore, I was hoping VBA would help, but I can only seem to get a function and not with a Sub and Function to transpose then count. Something like below...
Sub Main()
Dim filename As String
Dim WorksheetName As String
Dim CellRange As String
Sheets.Add.Name = "ParsedOutput"
'==============================================================
' CHANGE THESE VALUES FOR YOUR SHEET
WorksheetName =
CellRange =
'==============================================================
' Get range
Dim Range
Set Range = ThisWorkbook.Worksheets(WorksheetName).Range(CellRange)
' Copy range to avoid overwrite
Range.Copy _
Destination:=ThisWorkbook.Worksheets("ParsedOutput").Range("A1")
' Get copied exclusions
Dim Copy
Set Copy = ThisWorkbook.Worksheets("ParsedOutput").Range("A:A")
' Parse and overwrite
Copy.TextToColumns _
Destination:=Range("A:A"), _
DataType:=xlDelimited, _
ConsecutiveDelimiter:=True, _
Comma:=True
End Sub
Option Explicit
Public Function Counter(InputRange As Range) As String
Dim CellValue As Variant, UniqueValues As New Collection
Application.Volatile
'For error Handling On Error Resume Next
'Looping through all the cell in the defined range For Each CellValue In InputRange
UniqueValues.Add CellValue, CStr(CellValue) ' add the unique item Next
'Returning the count of number of unique values CountUniqueValues = UniqueValues.Count
End Function
For the sake of simplicity, I will take minimal data to demostrate how to achieve what you want. Feel free to change the code to suit your needs.
Excel Sheet
Let's say our worksheet looks like this
Logic:
Find last row and last column as shown HERE and construct your range.
Store the values of that range in an array.
Loop through each item in that array and extract words based of , as a delimiter and store it in the collection. If the delimiter doesnt exist then store the entire word in the collection. To create a unique collection, we use On Error Resume Next as shown in the code below.
Based on the count of words in the collection, we create an 2D array for output. One part of the array will hold the word and the other part will hold the count of occurences.
Use .Find and .FindNext to count the occurence of a word in the range and then store it in array.
Write the array in one go to the relevant cell. For demonstration purpose, I will write to Column D
Code
I have commented the code so you should not have a problem understanding it but if you do then simply ask.
Option Explicit
Sub Sample()
Dim ws As Worksheet
'~~> Change this to relevant sheet
Set ws = Sheet1
Dim LastRow As Long, LastColumn As Long
Dim i As Long, j As Long, k As Long
Dim col As New Collection
Dim itm As Variant, myAr As Variant, tmpAr As Variant
Dim OutputAr() As String
Dim aCell As Range, bCell As Range, rng As Range
Dim countOfOccurences As Long
With ws
'~~> Find last row
LastRow = .Cells.Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
'~~> Find last column
LastColumn = .Cells.Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Column
'~~> Construct your range
Set rng = .Range(.Cells(1, 1), .Cells(LastRow, LastColumn))
'~~> Store the value in an array
myAr = rng.Value2
'~~> Create a unique collection
For i = LBound(myAr) To UBound(myAr)
For j = LBound(myAr) To UBound(myAr)
If Len(Trim(myAr(i, j))) <> 0 Then
'~~> Check data has "," delimiter
If InStr(1, myAr(i, j), ",") Then
tmpAr = Split(myAr(i, j), ",")
For k = LBound(tmpAr) To UBound(tmpAr)
On Error Resume Next
col.Add tmpAr(k), CStr(tmpAr(k))
On Error GoTo 0
Next k
Else
On Error Resume Next
col.Add myAr(i, j), CStr(myAr(i, j))
On Error GoTo 0
End If
End If
Next j
Next i
'~~> Count the number of items in the collection
i = col.Count
'~~> Create output array for storage
ReDim OutputAr(1 To i, 1 To 2)
i = 1
'~~> Loop through unique collection
For Each itm In col
OutputAr(i, 1) = Trim(itm)
countOfOccurences = 0
'~~> Use .Find and .Findnext to count for occurences
Set aCell = rng.Find(What:=OutputAr(i, 1), LookIn:=xlValues, _
Lookat:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
Set bCell = aCell
countOfOccurences = countOfOccurences + 1
Do
Set aCell = rng.FindNext(After:=aCell)
If Not aCell Is Nothing Then
If aCell.Address = bCell.Address Then Exit Do
countOfOccurences = countOfOccurences + 1
Else
Exit Do
End If
Loop
End If
'~~> Store count in array
OutputAr(i, 2) = countOfOccurences
i = i + 1
Next itm
'~~> Output it to relevant cell
.Range("D1").Resize(UBound(OutputAr), 2).Value = OutputAr
End With
End Sub
Output
The following is a rough approach, and is open to tons of improvements, but should get you started.
Read the comments and adjust the code to fit your needs.
Option Explicit
Public Sub CountWordsInColumn()
' Adjust to set the sheet holding the data
Dim sourceSheet As Worksheet
Set sourceSheet = ThisWorkbook.Worksheets("DataSet")
' Adjust the column and row that contains the hits
Dim hitsColumn As String
Dim hitsStartRow As Long
Dim lastRow As Long
hitsColumn = "C"
hitsStartRow = 2
lastRow = sourceSheet.Cells(sourceSheet.Rows.Count, hitsColumn).End(xlUp).Row
' Adjust the column that contains the hits
Dim sourceRange As Range
Set sourceRange = sourceSheet.Range(hitsColumn & hitsStartRow & ":" & hitsColumn & lastRow)
' Add values in each cell split by ,
Dim evalCell As Range
Dim splitValues As Variant
Dim counter As Long
ReDim splitValues(lastRow - hitsStartRow)
For Each evalCell In sourceRange
splitValues(counter) = Split(evalCell.Value, ",")
counter = counter + 1
Next evalCell
' Get all values into an array
Dim allValues As Variant
allValues = AddValuesToArray(splitValues)
' Get unique values into an array
Dim uniqueValues As Variant
uniqueValues = GetUniqueValues(allValues)
' Count duplicated values from unique array
Dim outputData As Variant
outputData = CountValuesInArray(uniqueValues, allValues)
' Add new sheet
Dim outputSheet As Worksheet
Set outputSheet = ThisWorkbook.Sheets.Add
PrintArrayToSheet outputSheet, outputData
End Sub
Private Function AddValuesToArray(ByVal myArray As Variant) As Variant
Dim counter As Long
Dim tempArray As Variant
Dim tempCounter As Long
Dim tempArrayCounter As Long
ReDim tempArray(0)
For counter = 0 To UBound(myArray)
For tempCounter = 0 To UBound(myArray(counter))
tempArray(tempArrayCounter) = myArray(counter)(tempCounter)
tempArrayCounter = tempArrayCounter + 1
ReDim Preserve tempArray(tempArrayCounter)
Next tempCounter
Next counter
ReDim Preserve tempArray(tempArrayCounter - 1)
AddValuesToArray = tempArray
End Function
Private Function GetUniqueValues(ByVal tempArray As Variant) As Variant
Dim tempCol As Collection
Set tempCol = New Collection
On Error Resume Next
Dim tempItem As Variant
For Each tempItem In tempArray
tempCol.Add tempItem, CStr(tempItem)
Next
On Error GoTo 0
Dim uniqueArray As Variant
Dim counter As Long
ReDim uniqueArray(tempCol.Count - 1)
For Each tempItem In tempCol
uniqueArray(counter) = tempCol.Item(counter + 1)
counter = counter + 1
Next tempItem
GetUniqueValues = uniqueArray
End Function
Function CountValuesInArray(ByVal uniqueArray As Variant, ByVal allValues As Variant) As Variant
Dim uniqueCounter As Long
Dim allValuesCounter As Long
Dim ocurrCounter As Long
Dim outputData As Variant
ReDim outputData(UBound(uniqueArray))
For uniqueCounter = 0 To UBound(uniqueArray)
For allValuesCounter = 0 To UBound(allValues)
If uniqueArray(uniqueCounter) = allValues(allValuesCounter) Then ocurrCounter = ocurrCounter + 1
Next allValuesCounter
' This is the output
Debug.Print uniqueArray(uniqueCounter), ocurrCounter
outputData(uniqueCounter) = Array(uniqueArray(uniqueCounter), ocurrCounter)
ocurrCounter = 0
Next uniqueCounter
CountValuesInArray = outputData
End Function
Private Sub PrintArrayToSheet(ByVal outputSheet As Worksheet, ByVal outputArray As Variant)
Dim counter As Long
For counter = 0 To UBound(outputArray)
outputSheet.Cells(counter + 1, 1).Value = outputArray(counter)(0)
outputSheet.Cells(counter + 1, 2).Value = outputArray(counter)(1)
Next counter
End Sub
Try,
It is convenient to use Dictionary to extract duplicate items.
Sub test()
Dim Ws As Worksheet, wsResult As Worksheet
Dim vDB, vSplit, v
Dim Dic As Object 'Scripting.Dictionary
Dim i As Long, n As Long
Set Dic = CreateObject("Scripting.Dictionary")
Set Ws = Sheets(1) 'ActiveSheet
vDB = Ws.Range("a1").CurrentRegion
For i = 2 To UBound(vDB, 1)
vSplit = Split(vDB(i, 3), ",")
For Each v In vSplit
If Dic.Exists(v) Then
Dic(v) = Dic.Item(v) + 1
Else
Dic.Add v, 1
End If
Next v
Next i
Set wsResult = Sheets(2)
n = Dic.Count
With wsResult
.UsedRange.Clear
.Range("a1").Resize(n) = WorksheetFunction.Transpose(Dic.Keys)
.Range("b1").Resize(n) = WorksheetFunction.Transpose(Dic.Items)
End With
End Sub
For all who won't use VBA.
Here a solution with PowerQuery:
Quelle = Excel.CurrentWorkbook(){[Name="tbl_Source"]}[Content],
Change_Type = Table.TransformColumnTypes(Quelle,{{"ID", Int64.Type}, {"Record", type text}, {"Hits", type text}}),
Split_Hits = Table.ExpandListColumn(Table.TransformColumns(Change_Type, {{"Hits", Splitter.SplitTextByDelimiter(",", QuoteStyle.Csv), let itemType = (type nullable text) meta [Serialized.Text = true] in type {itemType}}}), "Hits"),
Clean_Spaces = Table.ReplaceValue(Split_Hits," ","",Replacer.ReplaceText,{"Hits"}),
Group_Rows = Table.Group(Clean_Spaces, {"Hits"}, {{"Count", each Table.RowCount(_), Int64.Type}})
in
Group_Rows
Approach simulating newer TextJoin and Unique functions
In order to complete the above solutions, I demonstrate an approach using
[1]a) a replacement of the TextJoin function (available since vers. 2019, MS 365 ~> the newer function code is commented out,btw),
[1]b) the FilterXML() function to get unique words (available since vers. 2013+) and
[3]a) a negative filtering to calculate results
Sub wordCounts()
'[0]define data range
With Sheet3
Dim lastRow As Long: lastRow = .Range("A" & .Rows.Count).End(xlUp).Row
Dim rng As Range: Set rng = .Range("A2:A" & lastRow)
End With
With WorksheetFunction
'[1]split a) available and b) unique words into arrays
' Dim words: words = Split(.TextJoin(",", True, rng), ",") ' (available vers. 2019+ or MS 365)
Dim words: words = Split(Join(.Transpose(rng), ","), ",") '
Dim uniques: uniques = UniqueXML(words) ' (already since vers. 2013+)
'[2]provide for calculation
'fill temporary array with words
Dim tmp: tmp = words
'declare cnt array for counting results
Dim cnt: ReDim cnt(0 To UBound(uniques), 0 To 0)
Dim old As Long: old = UBound(tmp) + 1 ' remember original size
'[3]get word counts
Dim elem
For Each elem In uniques
'a) filter out current elem
tmp = Filter(tmp, elem, False)
Dim curr As Long: curr = UBound(tmp) + 1
'b) count number of words (as difference of filtered tmp boundaries) ...
Dim n As Long: n = old - curr
' ... and remember latest array boundary
old = curr
'c) assign results to array cnt
Dim i As Long: cnt(i, 0) = n
i = i + 1 ' increment counter
Next elem
'[4]write word counts to target
rng.Offset(0, 2).Resize(UBound(uniques), 1) = .Transpose(uniques)
rng.Offset(0, 3).Resize(UBound(cnt), 1) = cnt
End With
End Sub
Help function UniqueXML()
Function UniqueXML(arr, Optional Delim As String = ",", Optional ZeroBased As Boolean = False)
' Purp: return unique list of array items
' Note: optional argument Delim defaulting to colon (",")
' Help: https://learn.microsoft.com/de-de/office/vba/api/excel.worksheetfunction.filterxml
' [1] get array data to xml node structure (including root element)
Dim wellformed As String
wellformed = "<root><i>" & Join(arr, "</i><i>") & "</i></root>"
' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
' [2] define XPath string searching unique item values
' Note: c.f. udf: https://stackoverflow.com/questions/58677041/vba-excel-how-to-display-non-equal-values-in-an-excel-array/58685756#58685756
' ------------------------------------------------
' //i ... all <i> node values after the DocumentElement
' [not( .=preceding::i)] ... only if not preceded by siblings of the same node value
' ------------------------------------------------
Dim myXPath As String
myXPath = "//i[not( .=preceding::i)]"
' [3] get "flat" 1-dim array (~> one-based!)
Dim tmp As Variant
tmp = Application.Transpose(WorksheetFunction.FilterXML(wellformed, myXPath))
' [3a] optional redim as zero-based array
If ZeroBased Then ReDim Preserve tmp(LBound(tmp) - 1 To UBound(tmp) - 1)
' [4] return function result
UniqueXML = tmp
End Function
I didn't understand the problem you have between sub or function; however, this is a function that counts the unique values in a range
Public Function Counter(InputRange As Variant) As Variant
Dim UniqueValues As New Collection
Dim Val As Variant
Dim Cell As Range
Dim I As Long
Application.Volatile
On Error Resume Next
For Each Cell In InputRange
Val = Split(Cell, ",")
If IsArray(Val) Then
For I = LBound(Val) To UBound(Val)
UniqueValues.Add Val(I), CStr(Val(I))
Next I
Else
UniqueValues.Add Val, CStr(Val)
End If
Next Cell
On Error GoTo 0
Counter = UniqueValues.Count
End Function
I have a sheet that I need to paste data to according to the validation lists in those sheets. In the sheet, there are many columns each with their own data validation list - some are written directly as "yes;no" others are references "='$$VALUES$$'!$IJ$1:$IJ$12".
What I need is to find a way to add each item in each list to an array. Using the code below I could find the references above.
Debug.Print Cells(2, 6).Validation.Formula1
Is there any elegant way to store the output as a list containing each valid input. My only idea so far is to first check which type of output I get, and then if it is the list form of "yes;no" then look for the number of ; and then split it item by item. And in case its the sheet range reference split it by sheet and range and convert that range to an array.
Something like this, will do it. I'd set a range rather than using activecell, and also check validation is present to reduce your errors.
Sub get_val_lists()
Dim arrOutput() As Variant
If Left(ActiveCell.Validation.Formula1, 1) <> "=" Then
arrOutput = Split(ActiveCell.Validation.Formula1, ",")
Else
arrOutput = Application.Transpose( _
Range(Mid(ActiveCell.Validation.Formula1, 2)).value)
End If
End Sub
I was a bit pressed for time so I ended up doing an inelegant solution myself. Posting it here in case somebody else runs into the same problem.
Sub ValidList()
Dim strFormula As String
Dim intLastSemi As Integer
Dim intCurSemi As Integer
Dim intSemi As Integer
Dim aryList() As Variant
Dim intLen As Integer
Dim blnCont As Boolean
Dim strSheet As String
Dim strRange As String
Dim intSplit As Integer
Dim ws As Worksheet
Dim rng As Range
Dim e As Variant
Dim Row As Integer
Dim Col As Integer
'This is just an example, turning it into a fucntion based on row and col later
'so now my test validation list is just in A1
Row = 1
Col = 1
strFormula = Cells(Row, Col).Validation.Formula1
intLen = Len(strFormula)
If InStr(1, strFormula, "=") Then 'Sheet reference
intSplit = InStr(1, strFormula, "!")
strSheet = Right(Left(strFormula, intSplit - 1), intLen - intSplit - 3)
strRange = Right(strFormula, intLen - intSplit)
Set ws = Worksheets(strSheet)
Set rng = ws.Range(strRange)
aryList() = rng
ElseIf Not InStr(1, strFormula, ";") Then 'Hardcoded list
intSemi = 0
intLastSemi = 0
blnCont = True
While blnCont
intCurSemi = InStr(intLastSemi + 1, strFormula, ";")
If intCurSemi <> 0 Then
intSemi = intSemi + 1
ReDim Preserve aryList(intSemi)
aryList(intSemi) = Right(Left(strFormula, intCurSemi - 1), intCurSemi - intLastSemi - 1)
intLastSemi = intCurSemi
ElseIf intCurSemi = 0 Then
intSemi = intSemi + 1
ReDim Preserve aryList(intSemi)
aryList(intSemi) = Right((strFormula), intLen - intLastSemi)
blnCont = False
End If
Wend
End If
'For my attempt at passing the array to a function
'For Each e In aryList
' MsgBox e
'Next
'ReDim ValidList(UBound(aryList))
'ValidList = aryList
End Sub
How can I place a formula in the first empty cell on Column F?
F3 is empty cell.
Need for that empty cell be =F2
Note: I'm looking for code to look for first empty cell F and I need to be able to insert in the first empty cell =F3.
Currently working with following code copied from here
Dim sourceCol As Integer, rowCount As Integer, currentRow As Integer
Dim currentRowValue As String
sourceCol = 6 'column F has a value of 6
rowCount = Cells(Rows.Count, sourceCol).End(xlUp).Row
'for every row, find the first blank cell and select it
For currentRow = 1 To rowCount
currentRowValue = Cells(currentRow, sourceCol).Value
If IsEmpty(currentRowValue) Or currentRowValue = "" Then
Cells(currentRow, sourceCol).Select
Exit For 'This is missing...
End If
Next
Your existing code implies you want to consider truely Empty cells and cells that contain an empty string (or a formula that returns an empty string) Note 1. (Given you simply copied that code from elsewhere, that may not be the case)
You can use End(xlDown) to locate the first truely Empty cell, or Match to locate the first "Empty" cell in a range (either just empty string, or either empty strings or Empty cells, in different forms)
If you want to find the first truely Empty cell, or cell containing an empty string:
Function FindFirstEmptyOrBlankCell(StartingAt As Range) As Range
Dim rng As Range
'Set search range
With StartingAt.Worksheet
Set rng = .Range(StartingAt, .Cells(.Rows.Count, StartingAt.Column).End(xlUp).Offset(1, 0))
End With
' Find first empty or blank cell
Set FindFirstEmptyOrBlankCell = rng.Cells(StartingAt.Worksheet.Evaluate("Match(True, " & rng.Address & "=""""" & ", 0)"), 1)
End Function
If you want to find the first truely Empty cell, and ignore cells containing an empty string:
Function FindFirstEmptyCell(StartingAt As Range) As Range
Dim rng As Range
'Set search range
With StartingAt.Worksheet
Set rng = .Range(StartingAt, .Cells(.Rows.Count, StartingAt.Column).End(xlUp).Offset(1, 0))
End With
' Find first empty cell
If IsEmpty(StartingAt.Cells(1, 1)) Then
Set FindFirstEmptyCell = rng.Cells(1, 1)
ElseIf IsEmpty(StartingAt.Cells(2, 1)) Then
Set FindFirstEmptyCell = rng.Cells(2, 1)
Else
Set FindFirstEmptyCell = rng.End(xlDown).Cells(2, 1)
End If
End Function
And for completeness, if you want to find the fisrt cell containing an empty string, and ignore truely Empty cells:
Function FindFirstBlankCell(StartingAt As Range) As Range
Dim rng As Range
Dim idx As Variant
'Set search range
With StartingAt.Worksheet
Set rng = .Range(StartingAt, .Cells(.Rows.Count, StartingAt.Column).End(xlUp).Offset(1, 0))
End With
' Find first blank cell
idx = Application.Match(vbNullString, rng, 0)
If IsError(idx) Then
'There are no Blank cells in the range. Add to end instead
Set FindFirstBlankCell = rng.Cells(rng.Rows.Count, 1)
Else
Set FindFirstBlankCell = rng.Cells(idx, 1)
End If
End Function
In all cases, call like this
Sub Demo()
Dim ws As Worksheet
Dim r As Range
Set ws = ActiveSheet '<~~~ or specify required sheet
Set r = FindFirstEmptyOrBlankCell(ws.Range("F3"))
' literally what was asked for
'r.Formula = "=F3"
' possibly what was actually wanted
r.Formula = "=" & r.Offset(-1, 0).Address(0, 0)
End Sub
Note 1
If IsEmpty(currentRowValue) Or currentRowValue = "" Then is actually redundant. Any value that returns TRUE for IsEmpty(currentRowValue) will also return TRUE of currentRowValue = "" (The reverse does not apply)
From comment can that same Fuction repeat until the last empty cel? I think this is what you mean is to continue to fill blank cells down through the used range
If so, try this
Sub Demo()
Dim ws As Worksheet
Dim cl As Range
Dim r As Range
Set ws = ActiveSheet '<~~~ or specify required sheet
Set cl = ws.Range("F3")
Do
Set r = FindFirstEmptyOrBlankCell(cl)
If r Is Nothing Then Exit Do
r.Formula = "=" & r.Offset(-1, 0).Address(0, 0)
Set cl = r.Offset(1, 0)
Loop
End Sub
Note, I've modified FindFirstEmptyOrBlankCell above to aloow it to return Nothing when it needs to:
Function FindFirstEmptyOrBlankCell(StartingAt As Range) As Range
Dim rng As Range
'Set search range
With StartingAt.Worksheet
Set rng = .Range(StartingAt, .Cells(.Rows.Count, StartingAt.Column).End(xlUp).Offset(1, 0))
End With
' Find first empty or blank cell
On Error Resume Next ' Allow function to return Nothing
Set FindFirstEmptyOrBlankCell = rng.Cells(StartingAt.Worksheet.Evaluate("Match(True, " & rng.Address & "=""""" & ", 0)"), 1)
End Function
You'll need to change your rowCount, the way you have it, the loop will stop before the first blank row. I believe you should just be able to set use .Formula for the empty cell. Hope this helps:
Sub EmptyCellFillFormula()
Dim sourceCol As Integer, rowCount As Integer, currentRow As Integer
Dim currentRowValue As String
sourceCol = 6 'column F has a value of 6
rowCount = Cells(Rows.Count, sourceCol).End(xlUp).Row + 1
For currentRow = 1 To rowCount
currentRowValue = Cells(currentRow, sourceCol).Value
If IsEmpty(currentRowValue) Or currentRowValue = "" Then
Cells(currentRow, sourceCol).Formula = "=F3"
End If
Next
End Sub