I am trying to set my array equal to all column headers of tables in a worksheet.
If I were doing this in Excel, I would click on A1 and do Control+Shift+Right Arrow. I've found some 15 year old code attempting to simulate this, shown below, but it doesn't recognize the last Column.
Sub Ls_List_Click()
'variables used in for each loops
Dim Column_Array() As Variant
Dim EndRange As Range
ThisWorkbook.Worksheets(Me.Ls_List.Value).Select
Range("A1", Range("A1").End(xlRight)).Select
EndRange = Range("A1").End(xlRight).Offset(2, 0)
Range(EndRange, EndRange.End(xlRight)).Select
EndRange = EndRange.End(xlRight).Offset(2, 0)
Column_Array() = EndRange
'... couple of for each loops
End Sub
I get error 1004 on the following line:
Range("A1", Range("A1").End(xlRight)).Select
If you replace xlRight with xlToRight you should be good
I believe you're looking for something more like:
Sub Ls_List_Click()
'variables used in for each loops
Dim Column_Array() As Variant
Column_Array() = Range(Cells(1,1),Cells(1, Cells(1, 1).End(xlToRight).Column)).value
'... couple of for each loops
End Sub
There didn't appear to be rhyme or reason for the .select components beyond stepping through to see where things were (nice for testing... i guess?).
Just one line of code gets your array generated for all the contiguous headers in your first row.
Edit:
Checking back, because EndRange is used for looping, you may want to write:
Sub Ls_List_Click()
'variables used in for each loops
Dim Column_Array() As Variant, EndRange as Long 'reference to column number, not a range, so watch referencing
EndRange = Cells(1, 1).End(xlToRight).Column
Column_Array() = Range(Cells(1,1),Cells(1, EndRange)).value
'... couple of for each loops
End Sub
Two main issues with your code:
You misspelled xlRight - the correct value is xlToRight. That's why it is recommended to use Option Explicit, so such errors are detected at compile time.
You shouldn't use Select - what for? If you want to reference particular cells/range, just use Cells(row, column) (row and column are integers) or Range("A1:B3") (just example).
Having said that, to get values into an array, you should use:
firstRowArray = Range(Cells(1, 1), Cells(1, 1).End(xlToRight)).Value2
Expalnation:
I used Range overload, accepting two cells as top-left and bottom-right cells to define the range. Top left is Cell(1, 1), i.e. A1 and bottom left is Cells(1, 1).End(xlToRight), which you are already familiar with :)
Then I use Value2 property, which return array of values (you could use Value but it's slower).
Note that, the result will be two-diensional array with number of rows and number of columns same as in the range.
Related
Hi i want to show an output to a specific cell at B column but i really don't have any idea on how to make it to show. Example: if "A2" has the record i want "B2" to show the output. If "A100" has the record, i want "B100" to show the output
Sub Testing()
Dim cell As Range
For Each cell In Range("A2:A4")
If cell.Value = "yes.com" Then
Range("B2:B4").Value = "Correct"
End If
Next
End Sub
The code above shows the output data "Correct" from "B2" to "B4" but what i want it to show on only the specific cell. Please Help
Currently you are looping through a range object. Per cell. One a small dataset this is fine but in your current attempt you'll need to change:
Range("B2:B4").Value = "Correct" for cell.Offset(0,1).value = "Correct"
As per my comment, you can do this a bit smarter/faster. Looping through worksheet cells is slow, certainly on large datasets (a 1000 rows is not that many yet to be honest). Nonetheless it's good to know that a good practice is to go through arrays. Let me show you below:
Sub Testing()
Dim lr As Long, x As Long
Dim arr As Variant
With Sheet1 'Change accordingly
lr = .Cells(.Rows.Count, 1).End(xlUp).Row
arr = .Range("A2:B" & lr)
For x = LBound(arr) To UBound(arr)
If arr(x, 1) = "yes.com" Then
arr(x, 2) = "correct"
End If
Next x
.Range("A2:B" & lr).Value = arr
End With
End Sub
So you can see a few things that will be helpfull:
A reference to a sheet (through a CodeName to refer to a range's parent. Without it, the macro will simply reference the ActiveSheet which is for obvious reasons not always the correct one.
I have made use of a dynamic sized array. The lr variable will get the last used row in column A, so you don't have to work through full qualified references no more.
The arr variable is an array which takes the values from the specified range into memory. Running through data in memory is much quicker than a loop/iteration over worksheet cells. This will become much more noticable when you would have even larger datasets.
I wrote the array back to the range in one go instead of several writings.
Hopefully that helped =)
As previously mentioned a 1000 rows is still not that much. Allthough I suggest you stick with the Array approach, you can also Evaluate column A and fill column B accordingly in one go instead of stepping through a range object. It's an array formula in disguise so not very quick on actual large datasets.
Sub Testing()
Dim lr As Long
Dim rng As Range
With Sheet1 'Change accordingly
lr = .Cells(.Rows.Count, 1).End(xlUp).Row
Set rng = .Range("A2:B" & lr)
rng.Columns(2).Value = .Evaluate("IF(" & rng.Columns(1).Address & "=""yes.com"",""correct"","""")")
End With
End Sub
Just try:
Sub test()
Dim i As Long
For i = 1 To Rows.Count
If Cells(i, 1) = "yes.com" Then Cells(i, 2) = "Correct"
Next
End Sub
It will loop through entire A column.
Alternatively, you can enter in B1 formula:
=IF(A1="yes.com","Correct","")
and drag it all the way down.
I'm having some trouble trying to find VBA code to delete multiple specific cells if a certain cell contains a specific text. This spreadsheet can run close to 100k rows as well, but will vary depending on the data pull.
The specific VBA would be able to do the following:
If Cell J3 equals #N/A, Blank, or 0, then clear contents of cells J3:K3 and P3:X3, and then repeat til it reaches the bottom of column J.
Thanks in advance
How to clear contents for specified cells when another cell contains specific text or string
Dim cellToClear As Range
Dim cellToCheck As Range
Dim specificText As String
If cellToCheck.Value = specificText Then cellToClear.ClearContents
"I'm having some trouble trying to find VBA code "
These links contain VBA code that you can use when you no longer have trouble trying. They contain examples you can paste into your project and modify for your needs.
This link has examples of how to read the contents of a cell.
A range is a group of one or more cells in a worksheet. You can perform an operation on a range and it will affect all the cells inside the range. This link has examples of how to work with a range.
A loop is when the program repeats the same sequence of steps, usually until a specific condition is met. You can find examples of different loops here.
I prefer placing values into an array if you are going to be changing a bunch of cells in a routine. This generally makes the process much quicker.
Start out by setting your worksheet and range objects. Please take note that the below code is currently using index 1 for the worksheet here: Set ws = ThisWorkbook.Worksheets(1). If this is not the worksheet you are personally needing, then you will need to change this.
Then place the cell contents of the entire range into an array. As I mentioned earlier, this process is quicker than making adjustments to individual cells 1 at a time.
Loop the array, checking for either the specific error value #N/A or the other criteria. If this criteria is a match, you will enter another loop that quickly loops through the 'columns' in the row that will delete the values from only the columns you specified.
Once finished, rewrite the array back to the worksheet.
Sub main()
Dim ws As Worksheet, rng As Range, dataArr() As Variant
Set ws = ThisWorkbook.Worksheets(1)
Set rng = ws.Range("J3:X" & ws.Cells(ws.Rows.Count, "J").End(xlUp).Row)
' Place the entire contents of worksheet range into an array
dataArr = rng.Value
Dim i As Long, x As Long, clearRow As Boolean
For i = LBound(dataArr) To UBound(dataArr)
If IsError(dataArr(i, 1)) Then
If dataArr(i, 1) = CVErr(xlErrNA) Then clearRow = True
ElseIf dataArr(i, 1) = vbNullString Or dataArr(i, 1) = 0 Then
clearRow = True
End If
' Loop thru the columns (x) of the current row (i)
If clearRow Then
For x = 1 To 15
Select Case x
Case 1, 2, 7 To 15
dataArr(i, x) = ""
End Select
Next x
clearRow = False
End If
Next i
' Re-write the entire array back to the worksheet in one step
rng.Value = dataArr
End Sub
New to VBA
I'm confused as to why I need to run my module twice to get it to update my cells. My code:
Option Explicit
Sub m_Range_End_Method()
Dim lRow As Long
Dim lCol As Long
Dim currentRow As Long
Dim i As Integer
Dim rng As Range
Set rng = ActiveCell
Range("B:B").Select
lRow = Cells(Rows.Count, 1).End(xlUp).Row
lCol = Cells(1, Columns.Count).End(xlToLeft).Column
Sheets("MySheet").Select
' Loop Through Cells to set description in each cell
Do While rng.Value <> Empty
currentRow = ActiveCell.Row
If InStr(rng.Value, "PETROL") = 0 Then
Set rng = rng.Offset(1)
rng.Select
Else
Worksheets("MySheet").Cells(currentRow, 5) = "Shopping"
Worksheets("MySheet").Cells(currentRow, 6) = "Car"
Set rng = rng.Offset(1)
rng.Select
End If
Loop
End Sub
On the first run what happens in Excel 2016 is that Column B gets highlighted and that's it. I then have to press "Run" again in visual basics editor for it to then update all the entries at which point column B gets unselected. All I want to do is update the cells at the currentRow of a specified worksheet. I've been reading but have got myself into some confusion, someone said I should use the
Range("B:B").Select
statement and for some reason the spreadsheet update works but only if I run it twice. Without this Range command, for reasons I don't understand, the spreadsheet doesn't update - all that happens is that the box selection moves to entries with Petrol and stays there with the program running but not updating.
The aim of the program is to find in a sheet all occurrences of a word in column B, in this initial case that is PETROL (I'm going to expand to include many others). For that match on the same row I want it to update columns 5 and 6 with descriptions. The excel spreadsheet will have hundreds of rows of entries with varying descriptions in column B.
Any help would be much appreciated.
I guess you have to run it twice because the first time you run it, the ActiveCell could be anything, and your loop depends on it not being empty to start with, but after the first run you have selected column B (and other things)...
Read this previous answer on avoiding the use of Select and Activate, it will make your code more robust: How to avoid using Select in Excel VBA macros
Revised Code
See the comments for details, here is a cleaner version of your code which should work first time / every time!
Sub m_Range_End_Method()
Dim col As Range
Dim rng As Range
Dim currentRow As Long
' Use a With block to 'Fully Qualify' the ranges to MySheet
With ThisWorkbook.Sheets("MySheet")
' Set col range to the intersection of used range and column B
Set col = Intersect(.UsedRange, .Columns("B"))
' Loop through cells in col to set description in each row
For Each rng In col
currentRow = rng.Row
' Check upper case value match against upper case string
If InStr(UCase(rng.Value), "PETROL") > 0 Then
.Cells(currentRow, 5) = "Shopping"
.Cells(currentRow, 6) = "Car"
End If
Next rng
End With
End Sub
Hi I have dynamically changing Column numbers. I need to select 2 cells using that column number. As I cannot use cells command to select more than one cell and i cannot use Range as i don't know the column with respect to letters, Please help me find a solution for the same.
Thanks in advance
for example my code is :
Dim Row_num as integer
for x=1 to 100
Thisworkbook.Sheets("Sheet1").range((Row_num,x),(Row_num,x+1)).select
selection.merge
next
Correct Usage is:
<WorkBook>.<WorkSheet>.Range(<CornerCell>, <OpositeCornerCell>)
There are several other issues in your code fragment. See comments in this code
Dim Row_num as Long ' Use Long as there may be more than 32767 rows, and its faster
Dim x as Long ' Dim all your variables
With Thisworkbook.Worksheets("Sheet1") ' Use With so you can refer to this part repeatedly
For x = 1 to 100 Step 2 ' Maybe you meant every second cell, otherwise ranges will overlap
' Refer to two corners of the required Range
' Don't use Select
Range(.Cells(Row_num, x), .Cells(Row_num, x + 1)).Merge
Next
End With
In addition to chris' excellent answer, let me add two small but really helpful methods of the Range object: .Offset and .Resize:
With Range.Offset you can "move" a cell, i.e. Range("A1").Offset(3, 2) will result in B3. And .Resize will will do as the name says, resize the range, i.e. Range("A1").Resize(3, 2) will result in A1:B3.
Both elements can be combined, e.g. Range("A1").Offset(1, 1).Resize(3, 2) results in B2:C4.
In your case, you could use:
Option Explicit 'always use Option Explicit, as it forces you to declare variables
Sub MergeFields
Dim lngRow As Long
Dim rngTopLeft As Range
Set rngTopLeft = Thisworkbook.Worksheets("Sheet1").Range("A1") 'change A1 accordingly!
For lngRow = 1 To 100
rngTopLeft.Offset(lngRow).Resize(1, 2).Merge
Next lngRow
End Sub
Really new to VBA here... I've looked around and tried to piece together some code to fulfil my need. Think it's almost there, but I'm getting errors that are likely easy to overcome and yet I don't know how.
The code looks at the current sheet (STOCK), and takes a 'target' text value from cell A2. It then searches a named range in another sheet 'Other'. If it determines one of the cells ('cand') in Other to be equal to the target value, then a value of "True" will be applied to column G in the STOCK sheet, on the same row of the original target.
Hopefully this makes sense. I've copied in the code which will maybe shed more light on things.
Dim target As String
Dim cand As String
Dim currentrow As Integer
Sub search_named_range()
' This range is hard coded; we can try A:A if hard code version works '
For Each target In Worksheets("STOCK").Range("A2:A1000")
' retrieve the row of the current range, for use when setting target values '
currentrow = Range(target).Row
' FOR loop to search range of part numbers in Mojave '
For Each cand In Worksheets("Other").Range("N9:N150")
If StrConv(cand.Value, 2) = StrConv(target, 2) Then
Worksheets("STOCK").Range("G" + currentrow) = "True"
GoTo FORend
End If
Next cand
' If part is not found, do nothing and return to find next target '
FORend: Next target
End Sub
Currently I'm getting the error 'For Each control variable must be Variant or Object', but can't find anywhere that explains why this is. I'm sure it's pretty obvious, but a steer would be really appreciated.
Thanks.
You can't use a String variable in a For Each. You're using tartget and cand as the control variables in your For Each loops but you have defined them as strings. They need to be an object, and specifically an object that is contained the collection of objects you're iterating. You're iterating over a range, which is a collection of ranges, so your control variables need to be Range objects.
Sub search_named_range()
Dim rCell As Range
Dim rCand As Range
For Each rCell In Worksheets("STOCK").Range("A2:A1000").Cells
For Each rCand In Worksheets("Other").Range("N9:N150").Cells
If StrComp(rCand.Value, rCell.Value, vbTextCompare) = 0 Then
rCell.Offset(0, 6).Value = "True"
Exit For 'exits the rCand For, but no the rCell one
End If
Next rCand
Next rCell
End Sub
Other changes that weren't correcting errors:
I'm not sure why you declared your variables outside the sub, but I put them inside.
You don't need to define .Cells at the end of the For Each line, but I like to. You could iterate over .Rows or .Columns or .Areas with a Range (although .Cells is the default).
There's nothing wrong with StrConvert, but you could also use LCase() or, as I do, StrComp.
Since I already have a reference to a cell on the current row (rCell), I use that and Offset to fill in a column I want.