How to use column/row index as range in VBA - vba

Like using Cells(1, 1) instead of Range("A1"), what's the best way to use column/Row index as range in VBA?
I came up with 2 solutions to denote Range("A:A"):
Range(Cells(1, 1), Cells(Columns(1).Rows.count, 1))
Union(Columns(1), Columns(1))
Is there a better and more concise solution?
Edit: noted response from Tehscript and thanks for the same. I already tried that but it's giving below error:
Run-time error '13': Type mismatch.
Here's the code:
Sub tfind()
Dim r1 As Range
Set r1 = Columns(1)
MsgBox mCount("Test:", r1)
End Sub
Function mCount(find As String, lookin As Range) As Long
Dim cell As Range
For Each cell In lookin
If (Left(cell.Value, Len(find)) = find) Then mCount = mCount + 1
Next
End Function
Although it works fine if the 3rd line:
Set r1 = Columns(1)
is changed to:
Set r1 = Union(Columns(1), Columns(1))

There is no best way to do this, but there are ways that you can use according to your needs. For example if you want to loop through both rows and columns you should better use Cells():
Sub RowTimesColumn()
Dim i As Long, j As Long
For i = 1 To 10
For j = 1 To 5
Cells(i, j) = i * j
Next j
Next i
End Sub
On the other hand you can reference a range like Range("A1:B3") in either way depending on your needs. If you simply need the reference, you should use Range("A1:B3"). If you need to play with the rows and columns, you should better use Range(Cells(1, 1), Cells(3, 2)).
It is all about readability and functionality.
For your question, you might want to use the following:
Range("A:A") --> Columns(1)
Range("A:C") --> Range(Columns(1), Columns(3))
Edit: You are looping through the cells within Column A, in that case you need to use:
Columns("A").Cells or Columns(1).Cells

Related

Issue trying to filter long numbers

I have a column with lots of longer numbers in it. I want to filter my column for all numbers that DO NOT begin with 2. I tried writing it in code to select all of the 2's first, but that didn't work. Then I tried to do it by hand in Excel by saying filter, custom rule, does not begin with 2. But nothing changes. I don't see, for example, a zero before the numbers either. I tried to reformat them into numbers but they were already numbers. I am not sure why it isn't selecting either all the numbers that start with 2 or all the numbers that DON'T start with 2.
Here is the code I tried to get numbers that START with 2.
With ws1.Range("A1:Z" & UsdRws)
.autofilter Field:=6, Criteria1:="2*", Operator:=xlFilterValues
On Error Resume Next
UsdRws = ws1.Range("C" & Rows.Count).End(xlUp).Row
If UsdRws > 1 Then
Range("A2:A" & UsdRws).SpecialCells(xlCellTypeVisible).EntireRow.Delete
End If
On Error GoTo 0
.autofilter Field:=9
Cells.EntireColumn.AutoFit
End With
The filter does not change anything even though I have a lot of numbers beginning with 2. Here is a sample of the numbers I am using.
2190190000
1410650400
1410720000
1410511900
1410650000
1410511900
1410650500
1410680100
1410650300
2190160000
1410650100
2190160000
2020110008
1410511900
1410650400
2020110002
2020180000
2010110100
1410671000
2190190000
1410650200
2020180000
2190190000
1410650400
1410720000
1410511900
1410650000
1410511900
1410650500
So like I said, I am trying to get either all the numbers beginning with 2 or all the other ones, but it seems like neither is working, even when doing it by hand using a custom filter rule.
If all of your numbers are 10 digit numbers, then the following seems to work:
Option Explicit
Sub FilterTwos()
Dim ws1 As Worksheet
Dim r As Range
Set ws1 = Worksheets("sheet1")
With ws1
Set r = .Range("a2", Cells(.Rows.Count, "A").End(xlUp))
End With
ws1.AutoFilterMode = False
r.AutoFilter Field:=1, Criteria1:=">=2000000000", Operator:=xlAnd, _
Criteria2:="<3000000000"
Set r = r.SpecialCells(xlCellTypeVisible)
r.Copy Worksheets("sheet2").Range("B2")
End Sub
In your With statement you use UsdRws but don't give UsdRws a value until within the 'With'. May this be causing your problem?
You could also try treating the numbers as strings (change format to text?). This way Excel shouldn't get confused by what it thinks you should or shouldn't be able to do with numbers.
This works regardless of how many digits your numbers contain. Your inputRange should just be the column with the long numbers in, include headers too.
Sub Remove2()
Dim inputRange As Range
Dim v As Variant
Dim i As Long, deleteCount As Long, min As Long
Set inputRange = Sheet1.Range("A1:A10001")
v = inputRange.Value
min = Application.WorksheetFunction.min(inputRange) - 1
For i = 1 To UBound(v)
If Left(v(i, 1), 1) = "2" Then
v(i, 1) = min
deleteCount = deleteCount + 1
End If
Next i
With inputRange
.Value = v
.Sort key1:=.Resize(1, 1), order1:=xlAscending, Header:=xlYes 'xlNo if no headers
.Resize(deleteCount, 1).Offset(1, 0).EntireRow.Delete 'remove offset if no headers
End With
End Sub
tested with 10,000 numbers taking 0.4 seconds

excel vba fill column from 1 to N

I am trying to write a VBA code to autofill range A1:A10000 with numbers 1 to 10000 but without entering 1 in A1 and 2 in A2 to create a range.
Basically, I need a code that looks like this:
Set fillRange = Worksheets("Sheet1").Range("A1:A10000")
(1,2).AutoFill Destination:=fillRange
Of course this does not work, but you get what it.
Writing and reading to/from the worksheet are some of the slowest actions you can perform. Writing time-efficient code means doing as much in memory as you can.
Try writing all your values into an array, then writing the whole thing to the worksheet in one shot, something like this:
Sub printRange(total As Integer)
Dim i, myRange() As Integer
ReDim myRange(1 To total)
For i = 1 To total:
myRange(i) = i
Next i
'Use Transpose to shift the 1d array into a column
Worksheets("Sheet1").Range("A1:A" & UBound(myRange)).Value = _
Application.WorksheetFunction.Transpose(myRange)
End Sub
For total = 10000, this pretty much runs instantly, even on a ten year old dinosaur desktop.
Dim fillRange As Range
Dim i As Long
Set fillRange = Worksheets("Sheet1").Range("A1:A10000")
With fillRange
For i = .Cells(1, 1).Row To .Cells(.Rows.Count, 1).Row
.Cells(i, 1).Value = i
Next i
End With 'fillRange
Or with AutoFill :
With Worksheets("Sheet1")
Range("A1").Value = 1
Range("A2").Value = 2
Range("A1:A2").AutoFill Destination:=Range("A1:A10000")
End With 'Worksheets("Sheet1")
this should be fast enough
you could use the following function
Function FillNumbers(rng As Range) As Variant
Dim i As Long
ReDim nmbrs(1 To rng.Rows.Count)
For i = 1 To UBound(nmbrs)
nmbrs(i) = i
Next
FillNumbers = Application.Transpose(nmbrs)
End Function
in the following manner
With Worksheets("Sheet1").Range("A1:A10000")
.Value = FillNumbers(.Cells)
End With
Can't you use a simple loop?
For i = 1 to 10000
Worksheets("Sheet1").Cells(i, 1) = i
Next i
Dim fillRagne As Range
Set fillRange = Range(Cells(1, 1), Cells(1000, 1))
For Each cell in fillRange
cell.value = cell.Row
Next cell

EXCEL-VBA Change a range with a loop

Set rng = Worksheets("Sheet1").Range("B2")
I have the above and would like to run a loop that changes the range I use/evaluate. I have tried variations of the following.
for x = 2 to 10
Set rng = Worksheets("No-Funding").Range(x & "2")
Next X
I have done some investigating and found this other Stack Overflow: Excel VBA Looping formula to change Range I can not make sense of it in this situation though.
My code will not work if it uses cells either, I have tried that and can only make it work with Range. Thanks for any help provided!
For a strictly numerical increment try,
Set rng = Worksheets("No-Funding").Cells(x, 2)
An xlA1 style reference can be achieved by factoring in the ASCII character.
Set rng = Worksheets("No-Funding").Range(Chr(64 + x) & 2)
Try this:
For x = 2 To 10
Set rng = Worksheets("No-Funding").Cells(2, x)
Next x
As far as I know it is no matter for VBA if you use function .Range or .Cells, since both of them return object or Range type.
Use
Set rng = Worksheets("Sheet1").Range("B2").Offset(0,x)
to move to a different column. Better yet
Dim values as Variant, rng as Range
Set rng = Worksheets("Sheet1").Range("B2").Resize(10,1)
values = rng.Values2
For i=1 to 10
values(i,1) = 2*values(i,1)
Next i
rng.Values2 = values

Excel Macro: If Column B contains 12 digits then column C equals 3?

So, I'm trying to figure out how to write an Excel macro to populate Column C with either 3 or a 4 depending on the amount of numbers contained in Column B.
I have searched up and down for the right wording to this, but I keep coming up short.
Basically, I need the macro to look at the number of digits in Column B. If there are 12 digits then the number is a UPC, and if there are 13 then the number is an EAN. I then need the macro to populate Column C with a 3 for UPCs and a 4 for EANs. This needs to be for the entire range of rows in the spreadsheet.
Does anyone have any ideas? Thanks a lot in advance!
You don't need to use a dirty old loop, try this (much faster if you have lots of rows):
Sub HTH()
With Sheet1.Range("B1", Cells(Rows.Count, "B").End(xlUp)).Offset(, 1)
.Formula = "=IF(LEN(TRIM(B1))=12,3,IF(LEN(TRIM(B1))=13,4,""""))"
.Value = .Value
End With
End Sub
Or use a user defined function, which has the advantage of changing when the data in column B is updated.
Better yet just use a formula, you don't really need VBA.
Alternative VBA Method (looping the fast way):
Sub HTH()
Dim vArray As Variant
Dim lCnt As Long
With Range("B1", Cells(Rows.Count, "B").End(xlUp))
vArray = .Value
For lCnt = 1 To UBound(vArray, 1)
Select Case Len(Trim(vArray(lCnt, 1)))
Case 12: vArray(lCnt, 1) = 3
Case 13: vArray(lCnt, 1) = 4
Case Else:
End Select
Next lCnt
.Offset(, 1).Value = vArray
End With
End Sub
You can get the length of a cell's value by using Len() like this Len(Range("A1")) for example.
Now you just need to loop through your column and look at each value. If you look for the last used cell and loop only through that range your loop will be faster.
Here is how I would do it:
sub TestUPC()
With ActiveSheet
LastRow = .Cells(.Rows.Count, "B").End(xlUp).Row
End With
Dim rRng As Range
Set rRng = Range("B1:B" & LastRow)
For Each cell In rRng.Cells
If Len(Trim(cell))=12 then
cell.Offset(0, 1).Value = 3
ElseIf Len(Trim(cell))=13 then
cell.Offset(0, 1).Value = 4
End If
Next
End Sub
An in cell equation could look like this:
=IF(LEN(B1)=12,3,IF(LEN(B1)=13,4," "))
As suggested in the comments you might want to test for spaces depending on your data:
=IF(LEN(TRIM(A1))=12,3,IF(LEN(TRIM(A1))=13,4," "))

Setting up a dynamic range in excel-vba

I'm basing my code off of this.
Excel VBA - select a dynamic cell range
I'm trying to find the syntax to create a dynamic range. Example: I always start on D8 but the upper bound of the range is based on an int count in another cell. [h4]
Dim count As Integer
count = Sheet2.Cells(8,1).Value
Set refRng = Sheet2.Range("D8:" & Cells(8, i).Address)
Is the relevant code sample.
I now know that Sheet2.Range("H1") doesn't return an int, it returns a variant or something?
I've tried a million different things and have figured out that none of them work. There has to be a better way to set up a dynamic range.
Not 100% sure what you're trying to achieve but in terms of messing around with ranges maybe this is a start:
Option Explicit
Sub select_Range()
Dim count As Integer
count = ThisWorkbook.Worksheets("Sheet2").Range("A8").Value
Dim i As Integer
i = count
Dim refRng As Excel.Range
Set refRng = ThisWorkbook.Worksheets("Sheet2").Range("D8:D" & i)
refRng.Select
End Sub
This results in the following on Sheet2:
This was originally a comment, but it is also the solution so I am adding it as an answer
Cells(8, 1) = "A8". If you want cell H1 it would be Cells(1, 8) or Cells(1, "H"). If you want cell H4 it would be Cells(4, 8) or Cells(4, "H").
Alternately, just Range("H1") or Range("H4")