Storing a Dynamic Range in Range variable - excel

I am trying to get unique values from dynamic F column and store it in an array. I am getting "Object Required error for my code while setting Selection variable to a dynamic range. Please help.
Sub UniqueFilter()
Dim tmp As String
Dim arr() As String
Dim Selection As Range
Dim lrow As Long
Dim str As String
Dim cell As Range
Dim sht As Worksheet
Set sht = ThisWorkbook.Worksheets("14Feb19")
sht.Activate
'Set Selection = sht.Range(sht.Cells(1, 6), sht.Cells(Rows.Count, 6).End (xlUp)).Select
lrow = shData.Range("F" & Rows.Count).End(xlUp).Row
Set Selection = sht.Range("F2:F" & lrow).Select
If Not Selection Is Nothing Then
For Each cell In Selection
If (cell <> "") And (InStr(tmp, cell) = 0) Then
tmp = tmp & cell & "|"
End If
Next cell
End If
If Len(tmp) > 0 Then tmp = Left(tmp, Len(tmp) - 1)
arr = Split(tmp, "|")
End Sub

You can achieve your goal without having to use Selection at all.
Just copy the range content and transpose it into an array:
Sub UniqueFilter()
Dim arr() As String
Dim tmp As Variant
Dim lrow As Long
Dim sht As Worksheet
Dim index As Integer
Dim count As Integer
Set sht = ThisWorkbook.Worksheets("14Feb19")
sht.Activate
lrow = sht.Range("F" & Rows.count).End(xlUp).Row
'Copying and trasposing selected Range
tmp = Application.Transpose(sht.Range("F2:F" & lrow).Value)
'Cleaning from temp array all empty values
count = 1
For index = 1 To UBound(tmp, 1) - LBound(tmp, 1) + 1
ReDim Preserve arr(1 To count)
If tmp(index) <> "" Then
arr(count) = tmp(index)
count = count + 1
End If
Next
End Sub
(special thanks to #Nathan_Sav, who helped simplifying the code)

Related

Error 400 when trying to operate with all used cells in Excel with VBA

I'm trying to take the first column from my file (all rows except header) and delete text to the left of a colon character but I get a 400 error from VBA. I don't know what's wrong with this code.
As an example A2 (and subsequent cells in the A column) look like this:
Sub cleanLoginTime()
Dim cell As Range
Dim MyRange As Range
Dim tmp As String
LastRow = Cells(Rows.Count, 1).End(xlUp)
Set MyRange = ActiveSheet.Range("A2:A" & LastRow) 'this is your range of data
For Each cell In MyRange.Cells
tmp = cell.Value
'output n - 1 characters from the right
cell.Value = Right(tmp, Len(tmp) - 21)
Next
End Sub
Remove Left From Strings in Column
Sub CleanLoginTime()
Const FindString As String = ":"
Dim FindStringLength As Long: FindStringLength = Len(FindString)
Dim ws As Worksheet: Set ws = ActiveSheet ' improve!
Dim rg As Range
Set rg = ws.Range("A2", ws.Cells(ws.Rows.Count, "A").End(xlUp))
Dim cell As Range
Dim FindStringPosition As Long
Dim CellString As String
For Each cell In rg.Cells
CellString = CStr(cell.Value)
FindStringPosition = InStr(CellString, FindString)
If FindStringPosition > 0 Then ' string found
cell.Value = Right(CellString, Len(CellString) _
- FindStringPosition - FindStringLength + 1)
'Else ' string not found; do nothing
End If
Next cell
End Sub
To make it more efficient (faster), you could introduce an array (Data), to access the worksheet minimally.
Sub CleanLoginTimeArray()
Const FindString As String = ":"
Dim FindStringLength As Long: FindStringLength = Len(FindString)
Dim ws As Worksheet: Set ws = ActiveSheet ' improve!
Dim rg As Range
Set rg = ws.Range("A2", ws.Cells(ws.Rows.Count, "A").End(xlUp))
Dim Data() As Variant: Data = rg.Value ' works only if more than one cell!
Dim r As Long
Dim FindStringPosition As Long
Dim CellString As String
For r = 1 To UBound(Data, 1)
CellString = CStr(Data(r, 1))
FindStringPosition = InStr(CellString, FindString)
If FindStringPosition > 0 Then ' string found
Data(r, 1) = Right(CellString, Len(CellString) _
- FindStringPosition - FindStringLength + 1)
'Else ' string not found; do nothing
End If
Next r
rg.Value = Data
End Sub
I get a run-time error '13' because you need .row in
lastrow = Cells(Rows.Count, 1).End(xlUp).row
Do any of your cells have a length < 21?

Matching 2 Separate Strings with 2 Separate Ranges to Copy the Corresponding Value

I have been trying to match Date with week number i.e. ("B1:F1")
then date with Year-month i.e. ("A2:A500")
If matches then copy the value from this table that i have highlighted according to the date which is available in code where week is 2 and month is May-2021. Can someone please help me to achieve this.
There are multiple dates which i need to iterate with this table to get different values according to weeks and Year-Months.
Your help will be much appreciated.
Sub findMatchingRecords()
Dim rng1 As Range
Dim rng2 As Range
Dim ws As Worksheet
Dim getdate As String
Dim GetWeek As String
Set ws = Worksheets("Sheet1")
getdate = ws.Range("N1").Value
GetWeek = Int((Day(getdate) + 6) / 7)
Set rng1 = ws.Range("B1:F1")
Set rng2 = ws.Range("A2:A500")
For Each rng1cell In rng1
For Each rng2cell In rng2
If rng1cell = GetWeek And rng2cell = Format(getdate, "yyyy-mmm") Then
'Copy value and paste into Sheet1.Range("M2")
End If
Next rng1cell
Next rng2cell
End Sub
Here are the dates which needs to match with table and get relevant the value.
5/13/2021
5/16/2021
5/19/2021
5/22/2021
5/25/2021
5/28/2021
5/31/2021
6/3/2021
6/6/2021
6/9/2021
6/12/2021
6/15/2021
6/18/2021
6/21/2021
6/24/2021
Non-VBA Method
One way this could be done without using VBA is with a INDEX/MATCH formula.
The following formula assumes the data is in B2:F500, the month/years are in A2:A500, the weeks in B1:F1 and the dates to look for are in column N, all on the same sheet Sheet1.
=INDEX($B$2:$F$13,MATCH(TEXT(N1,"yyyy-mmm"),Sheet1!$A$2:$A$13,0),MATCH(INT((DAY(N1)+6)/7),Sheet1!$B$1:$F$1,0))
VBA Method
If you want VBA to do this here's one way.
Option Explicit
Sub findMatchingRecords()
Dim ws As Worksheet
Dim rngData As Range
Dim rngDates As Range
Dim arrData As Variant
Dim arrDates As Variant
Dim arrYearMonth As Variant
Dim arrValues As Variant
Dim arrWeeks As Variant
Dim Res As Variant
Dim idxCol As Long
Dim idxDate As Long
Dim idxRow As Long
Dim wk As Long
Set ws = Sheets("Sheet1")
With ws
Set rngData = .Range("A1").CurrentRegion
Set rngDates = .Range("N1", .Range("N" & Rows.Count).End(xlUp))
End With
With rngData
arrData = rngData.Offset(1, 1).Resize(.Rows.Count - 1, .Columns.Count - 1)
arrYearMonth = .Columns(1).Offset(1).Resize(.Rows.Count - 1)
arrWeeks = .Rows(1).Offset(, 1).Resize(, .Columns.Count - 1)
End With
arrDates = rngDates.Value
ReDim arrValues(1 To UBound(arrDates, 1), 1 To 1)
For idxDate = LBound(arrDates, 1) To UBound(arrDates, 1)
idxRow = 0
idxCol = 0
Res = Application.Match(Format(arrDates(idxDate, 1), "yyyy-mmm"), arrYearMonth, 0)
If Not IsError(Res) Then
idxRow = Res
wk = Int((Day(arrDates(idxDate, 1)) + 6) / 7)
Res = Application.Match(wk, arrWeeks, 0)
If Not IsError(Res) Then
idxCol = Res
End If
End If
If idxRow <> 0 And idxCol <> 0 Then
arrValues(idxDate, 1) = arrData(idxRow, idxCol)
End If
Next idxDate
rngDates.Offset(, 1).Value = arrValues
End Sub
Please, test the next code:
Sub MatchDate_WeekNo()
Dim sh As Worksheet, lastR As Long, arr, arrN, arrfin, i As Long, strDate As String
Dim weekN As Long, arrRow, arrCol, iCol As Variant, iRow As Variant, lastRN As Long
Set sh = Worksheets("Sheet1")
lastR = sh.Range("A" & sh.Rows.Count).End(xlUp).Row
lastRN = sh.Range("N" & sh.Rows.Count).End(xlUp).Row
arr = sh.Range("A1:F" & lastR).Value
arrRow = Application.Index(arr, 1, 0)
arrCol = Application.Transpose(Application.Index(arr, 0, 1))
arrN = sh.Range("N2:N" & lastRN).Value2
ReDim arrfin(1 To UBound(arrN), 1 To 1)
For i = 1 To UBound(arrN)
strDate = StringFromDate(CDate(arrN(i, 1)))
weekN = Int((Day(arrN(i, 1)) + 6) / 7)
iCol = Application.Match(weekN, arrRow, 0)
iRow = Application.Match(strDate, arrCol, 0)
If IsNumeric(iCol) And IsNumeric(iRow) Then
arrfin(i, 1) = arr(iRow, iCol)
End If
Next i
'drop the final array content:
sh.Range("O2").Resize(UBound(arrfin), 1).Value = arrfin
End Sub
Function StringFromDate(d As Date) As String
Dim arrM
Const strMonths As String = "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec"
arrM = Split(strMonths, ",")
StringFromDate = Year(d) & "-" & Application.Index(arrM, Month(d))
End Function
Format(arrDates(idxDate, 1), "yyyy-mmm") does not return the month in case of localization different then English type and only that's why I am using a function...

Remove duplicates from a string array using excel VBA

I have the following VBA code in Excel 2010 that reads the numbers in column A into a comma separated string.
The numbers are sorted in column A
However, I was wondering if there was a way to either remove the duplicate numbers while reading them to to the comma separated variable, or a way to remove all the duplicates from the variable after it has been built.
Here is my code that builds the comma separated list
Dim LR As Long
Dim RangeOutput
Dim entry As Variant
Dim FinalResult As String
LR = Range("A" & Rows.Count).End(xlUp).Row
On Error Resume Next 'if only 1 row
For Each entry In ThisWorkbook.Sheets("Sheet1").Range("A2:A" & LR)
If Not IsEmpty(entry.Value) Then
RangeOutput = RangeOutput & entry.Value & ","
End If
Next
FinalResult = Left(RangeOutput, Len(RangeOutput) - 1)
This is how you can do it with a dictionary.
Dim arrData As Variant
Dim dic As Object
Dim idx As Long
arrData = Range("A2").CurrentRegion.Columns(1).Value
Set dic = CreateObject("Scripting.Dictionary")
For idx = 2 To UBound(arrData, 1)
If arrData(idx, 1) <> "" Then
dic(arrData(idx, 1)) = ""
End If
Next idx
FinalResult = Join(dic.keys, ",")
You can use a Collection to achieve same result:
Option Explicit
Sub Test()
Dim ws As Worksheet
'
On Error Resume Next
Set ws = ThisWorkbook.Worksheets("Sheet1")
On Error GoTo 0
If ws Is Nothing Then
MsgBox "Missing required worksheet", vbExclamation, "Cancelled"
Exit Sub
End If
'
Dim lastRowIndex As Long
'
lastRowIndex = ws.Range("A" & Rows.Count).End(xlUp).Row 'Notice the range is fully referenced with the sheet
If lastRowIndex = 1 Then
MsgBox "No data found in column A", vbInformation, "Cancelled"
Exit Sub
End If
'
Dim arrValues As Variant
'
arrValues = ws.Range("A2:A" & lastRowIndex).Value2
If Not IsArray(arrValues) Then arrValues = Array(arrValues) 'Just in case lastRow is 2
'
Dim v As Variant
Dim uniqueValues As New Collection
'
On Error Resume Next 'For duplicated values - collections do not allow duplicated keys
For Each v In arrValues
uniqueValues.Add v, CStr(v)
Next v
On Error GoTo 0
'
Dim arrResult() As Variant
Dim i As Long
Dim result As String
'
ReDim arrResult(0 To uniqueValues.Count - 1)
i = 0
For Each v In uniqueValues
arrResult(i) = CStr(v) 'In case there are errors like #N/A
i = i + 1
Next v
'
result = Join(arrResult, ",")
Debug.Print result
End Sub

Add to Listbox if cell value contains specific string

I am trying to add data to a Listbox on a Userform, based on the value of the the Cell in column C of the range that is searched. If the cell in column C contains a certain string I would like it to be added to the Listbox.
The below code is as far as I have got but it is returning an empty Listbox with no error.
Private Sub OptionButton12_Click()
Dim I As Integer
Dim lastRow As Integer
Dim searchString As String
searchString = "LISTBOXENTRY"
With ThisWorkbook.Sheets("Sheet1")
lastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
Plybooks.ListBox1.Clear
For I = 1 To lastRow
If Cells(I, 3).Value = searchString Then
Plybooks.ListBox1.AddItem Range("A" & I)
End If
Next I
End Sub
Try using the script below and please let me know if it works!
based on your script above, I assumed some of the dataframe dimensions. please let me know if it is not correct so I can tweak it.
I assumed you are working on first sheet (sheets(1)), and col C is the column you are using for the value check against the "searchString" variable. (if true, append the value in listbox1)
Thanks
Private Sub OptionButton12_Click()
Dim lastRow As Integer
Dim searchString As String
Dim wb As Workbook
Dim sRng As Range
Dim cel As Range
'assign current wb into wb workbook object
Set wb = ThisWorkbook
'assign str you want to search into variable
searchString = "LISTBOXENTRY"
'find last row number in colC (3) using crow function. (assuming you want to do a check on every cell listed in column C)
lastRow = crow(1, 3)
plybooks.listbox1.Clear
'assign range object using dataframe dimensions based on row 1 col C (lbound), to lastrow col3 (ubound)
With wb.Sheets(1)
Set sRng = .Range(.Cells(1, 3), .Cells(trow, 3))
End With
'loops through each cel
For Each cel In sRng
If cel.Value = searchString Then
'adds item into listbox1 if conditional statement is True
plybooks.listbox1.AddItem Item:=cel.Value
Else
End If
Next cel
End Sub
Private Function crow(s As Variant, c As Integer)
crow = Sheets(s).Cells(Rows.Count, c).End(xlUp).Row
End Function
Added cell values in ranges over multiple sheets if cell contains certain value, using the following:
Public Sub PlybookListbox()
'Clear fields before start
Plybooks.ListBox1.MultiSelect = 0
Plybooks.ListBox1.Clear
Plybooks.ListBox1.Value = ""
Plybooks.ListBox1.MultiSelect = 2
Dim AllAreas(2) As Range, Idx As Integer, MyCell As Range, TargetRange As Range
Dim lastrowFrontWing As Long
Dim lastrowNose As Long
Dim lastrowBargeboard As Long
lastrowFrontWing = Worksheets("Front Wing").Cells(Rows.Count, 2).End(xlUp).Row
lastrowNose = Worksheets("Nose").Cells(Rows.Count, 2).End(xlUp).Row
lastrowBargeboard = Worksheets("Bargeboard & SPV").Cells(Rows.Count, 2).End(xlUp).Row
Set AllAreas(0) = Worksheets("Front Wing").Range("c6:c" & lastrowFrontWing)
Set AllAreas(1) = Worksheets("Nose").Range("c6:c" & lastrowNose)
Set AllAreas(2) = Worksheets("Bargeboard & SPV").Range("c6:c" & lastrowBargeboard)
Plybooks.ListBox1.Clear
For Idx = 0 To 2
For Each MyCell In AllAreas(Idx).Cells
If InStr(1, MyCell.Value, "(FS)") > 0 Then
Plybooks.ListBox1.AddItem MyCell.Value
End If
Next MyCell
Next Idx
End Sub

Concatenate unique cell values in every row

How can I concatenate unique cell values in every row to adapt in the code below. Removing duplicate values in a cell. Result after macro is the second image.
Sub Concatenar()
Dim myRange As Range
Dim c As Long
Dim r As Long
Dim txt As String
Set myRange = Application.InputBox("Selecione a primeira e a Ășltima cĂ©lula:", Type:=8)
For r = 1 To myRange.Rows.Count
For c = 1 To myRange.Columns.Count
If myRange(r, c).Text <> "" Then
txt = txt & myRange(r, c).Text & vbLf
End If
Next
If Right(txt, 1) = vbLf Then
txt = Left(txt, Len(txt) - 1)
End If
myRange(r, 1) = txt
txt = ""
Next
Range(myRange(1, 2), myRange(1, myRange.Columns.Count)).EntireColumn.Delete
End Sub
This does what you want, I believe. It pastes/tranposes the values to a temporary workbook, uses RemoveDuplicates to trim them down, and Join to munge them all together. It then pastes the munged values back into column A of the original workbook and deletes the other columns.
Because of the destructive nature of this code, you must test it on a copy of your data:
Sub CrazyPaste()
Dim wsSource As Excel.Worksheet
Dim rngToConcat As Excel.Range
Dim wbTemp As Excel.Workbook
Dim wsPasted As Excel.Worksheet
Dim rngPasted As Excel.Range
Dim i As Long
Dim LastRow As Long
Dim Results() As String
Set wsSource = ActiveSheet
Set rngToConcat = wsSource.UsedRange
Set wbTemp = Workbooks.Add
Set wsPasted = wbTemp.Worksheets(1)
wsSource.UsedRange.Copy
wsPasted.Range("A1").PasteSpecial Transpose:=True
Set rngPasted = wsPasted.UsedRange
ReDim Results(1 To rngPasted.Columns.Count)
For i = 1 To rngPasted.Columns.Count
If WorksheetFunction.CountA(rngPasted.Columns(i)) = 0 Then
Results(i) = ""
Else
rngPasted.Columns(i).RemoveDuplicates Columns:=1, Header:=xlNo
LastRow = Cells(wsPasted.Rows.Count, i).End(xlUp).Row
Results(i) = Replace(Join(Application.Transpose(rngPasted.Columns(i).Resize(LastRow, 1)), vbCrLf), _
vbCrLf & vbCrLf, vbCrLf)
End If
Next i
With wsSource
.Range("A1").Resize(i - 1, 1) = Application.Transpose(Results)
.Range(.Cells(1, 2), .Cells(1, .Columns.Count)).EntireColumn.Delete
wbTemp.Close False
End With
End Sub
In my limited testing, the only situation where this might yield unwanted results is when a cell in the first column is blank, but there's other data in that row. The resulting cell would then start with a blank.

Resources