Forum Discussion
modify VBA code to include dynamic columns instead of static
I have the following code which looks for the word "unknown" in column "4" (of sheet "Raw Data") and then copies the corresponding row of data to a different sheet ("undiluted"). However, sometimes this data is found in different columns (column 3, 5, 6, etc). How would you code this so that it looks for the header ("Sample Type") and uses this column instead of just column "4"?
Thanks,
Greg
------------------------------------
Private Sub CommandButton1_Click()
a = Worksheets("Raw Data").Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To a
If Worksheets("Raw Data").Cells(i, 4).Value = "Unknown" Then
Worksheets("Raw Data").Rows(i).Copy
Worksheets("Undiluted").Activate
b = Worksheets("Undiluted").Cells(Rows.Count, 1).End(xlUp).Row
Worksheets("Undiluted").Cells(b + 1, 1).Select
ActiveSheet.Paste
Worksheets("Raw Data").Activate
End If
Next
Application.CutCopyMode = False
ThisWorkbook.Worksheets("Raw Data").Cells(1, 1).Select
End Sub
30 Replies
- PeterBartholomew1Silver Contributor
I am still somewhat puzzled as to the reason you turn so readily to VBA for the analysis. Excel has a huge amount of built-in functionality to support filtering, both as manual operations and automatic, using formulas,
I ran the code in "Example with VBA4.xlsm" this morning and it took 1min20sec to produce 630 rows for 'undiluted' and a further 30 on the 'diluted' sheet. I am sure there is plenty of room for speed optimisation of the code but I went on to compare that time with that of a formula-based approach.
I happened to be using a machine with Office 365 loaded so, having converted the source data to a table, I used a modern dynamic array formula to extract the required records. The formulas
= FILTER( RawData,
((RawData[Sample Type]="Unknown") +
(RawData[Sample Type]="Quality Control")) *
(RawData[Dilution Factor]=1) )
and
= FILTER( RawData,
((RawData[Sample Type]="Unknown") +
(RawData[Sample Type]="Quality Control")) *
(RawData[Dilution Factor]>1) )
each took 0.1sec to run and gave identical output.
p.s. Other options would include running the Advanced Filter from code (any version of Excel) or to use Power Query (Office 2010 with add-in, native 2016 and on).
I have now attached a copy of the file with your early VBA, with Power Query and with Dynamic Array formulas. The last only works with the most up-to-date versions of Office365.
- gms4bBrass Contributor
Thanks Peter. I'll start to look into this. In the end, the whole process is:
- dividing Unknown and Quality Control samples between diluted and undiluted groups (Then get rid of columns that I don't need)
- Adding some columns to each of these sets to do some math do determine if the samples are in a range
- Then a VLOOKUP to compare samples in the diluted and undiluted groups and choose the proper one for final data.
This has been a very manual process not just for me, but my teammates. I wanted to make a way for people to simply add in all the raw data into the first tab of a spreadsheet, press a button, and get final data. So, that's why I thought VBA would be a good way to automate the whole process.
If i can find a way to do the filtering (as you suggest) and replace the first part of the code, then that sounds like a good idea. As you mentioned.....it can be rather slow. And, its possible that 1000's of rows of data could be in a set.
Thanks,
Greg
- PeterBartholomew1Silver Contributor
Do you and any colleagues that need to manipulate the results have Office 365 and can you set it to monthly updates? The array methods I have used have only come out in the latest releases of Excel and, though it would be possible to transfer the data using INDEX it would lack elegance.
Removing columns could be achieved by being more selective as to the columns brought through in the first place, even down to the level of bring key columns across individually within the downstream calculation.
- PeterBartholomew1Silver Contributor
I suspect that with the newest releases of Office 365 most of the things described here can be done easily with worksheet formulas. The points to observe are that all raw data should be entered into Excel Tables so that the field to be searched for the value "Unknown" can be identified by name rather than a static numeric index. Given that tables adjust dynamically to the data, no counts are required to determine the length of the column.
The key function is FILTER which will return all the records that match the criterion
= FILTER( Table1, Table1[field]="Unknown"} )
The advantage of names is as great when it comes to VBA. A named field can be block-read into a variant array and then the looping is in memory rather than requiring continual exchanges between the VBA environment and the worksheet. If the column changes, the Name moves with it, so the code is more robust.
- Haytham AmairahSilver Contributor
Hi,
You can do this by a simple algorithm:
- Search for the header of (Sample Type) in the worksheet using the Cell.Find method in VBA
- Store the column number of the Sample Type header in a variable called: headerColumn
- Use this variable in place of the number 4 in the IF statement's logical test
So the code looks like this:
Sub test() Application.ScreenUpdating = False Dim a As Long a = Worksheets("Raw Data").Cells(Rows.Count, 1).End(xlUp).Row Dim headerColumn As Long headerColumn = Cells.Find(What:="Sample Type", After:=Range("A1"), LookIn:=xlFormulas, _ LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _ MatchCase:=False, SearchFormat:=False).Column For i = 2 To a If Worksheets("Raw Data").Cells(i, headerColumn).Value = "Unknown" Then Worksheets("Raw Data").Rows(i).Copy Worksheets("Undiluted").Activate Dim b As Long b = Worksheets("Undiluted").Cells(Rows.Count, 1).End(xlUp).Row Worksheets("Undiluted").Cells(b + 1, 1).Select ActiveSheet.Paste Worksheets("Raw Data").Activate End If Next Application.CutCopyMode = False ThisWorkbook.Worksheets("Raw Data").Cells(1, 1).Select Application.ScreenUpdating = True End Sub
Hope that helps
- gms4bBrass Contributor
oooo. Nice, it works! Thanks!!
Another question? What if I also wanted to look for "Quality Control" in addition to "Unknown"....so, any row that had "Quality Control" or "Unknown" in a column with "Sample Type" as the header would get moved to the "Undiluted" sheet.
Thanks!
Greg
- gms4bBrass Contributor
Nevermind....figured it out:
If (Worksheets("Raw Data").Cells(i, headerColumn).Value = "Unknown" Or Worksheets("Raw Data").Cells(i, headerColumn).Value = "Quality Control") Then
Thanks!