excel vba moving non-contiguous range selection to an array - vba

In the situation where the user select two non-contiguous column ranges i wrote the following:
Dim count long
Dim points variant
Dim i long
Set user_range = ActiveWindow.RangeSelection
count = user_range.count / 2
ReDim points(1 To count, 1 To 2)
For i = 1 To count
MsgBox "value is" & user_range.Areas.Item(1).Value(i,1)
points(i, 1) = user_range.Areas.Item(1).Value(i,1)
points(i, 2) = user_range.Areas.Item(2).Value(i,1)
Next i
But i get an object error when i try this. Am i indexing Value wrong?
This should work right? Is there an easier way to do this?
Any help is greatly appreciated!
Thanks,
Russ

I'm afraid your code does not compile. First of all, you need to declare your variables correctly. You should also use Option Explicit.
Option Explicit
Dim count As Long
Dim points As Variant
Dim i As Long
Dim user_range As Range
The count and ReDim lines are OK, but you are assuming that the two selections are both the same size. Will that always be the case?
Then I'm not sure what it is you want to do, but I'm guessing you just want to save the values in user_range into points.
You need to adress them a bit different:
points(i, 1) = user_range.Areas(1).Cells(i, 1).Value 'Selection 1
points(i, 2) = user_range.Areas(2).Cells(i, 1).Value 'Selection 2

Related

VBA Get Values from AutoFilter

Let's say I have very large set of data with over 100,000+ rows. In Column A, I want to find each unique number.
I understand this can be done using the .Find feature and Collections/Arrays but those seem to take a good bit of time - especially with 100,000+ rows.
However, after AutoFiltering Column A, when I hit the down arrow it displays only unique variables. Is it possible to simply extract those values out of the selections in this way?
'pseudocode
filter.Count
Dim X As Long
For x = 2 to filter.Count
Cells(x, 14) = filter(x)
Next x
You can use advanced filter, it's pretty darn quick. I tried it with 127k rows, the results were instant.
Columns("A:A").AdvancedFilter Action:=xlFilterCopy, CopyToRange:=Range("D1"), Unique:=True
You can extract the visible cells in to an array. Say your total range (without filter) is A2:A10000. Run your filter, then you can run this macro:
Sub t()
Dim arr() As Variant
arr = Range("A2:A10000").SpecialCells(xlCellTypeVisible)
Dim i As Long
For i = LBound(arr) To UBound(arr)
Debug.Print (arr(i, 1))
' Do things with each entry in array
Next i
End Sub

Consolidating finding non-blank range into 1 line

I am trying to count the number of non-blank cells in a column B. I know the syntax on this is off but I am not sure how to make it work correctly. I am trying to avoid doing a loop and and make it as simple as possible. Any thoughts would be greatly appreciated.
With Dashboard
Total_Emails = Dashboard.Cells(Dashboard.Rows.Count, "B").End(xlUp).Row - WorksheetFunction.CountBlank(Range("B1:B&Dashboard.Cells(Dashboard.Rows.Count, "B").End(xlUp).Row))
End With
Use CountA to count all the non-blanks in a range.
Total_Emails = WorksheetFunction.CountA(Columns("B"))
I figured that it is actually easier to split it up into several different expressions. This works correctly.
Dim CountLast As Long
CountLast = Dashboard.Cells(Dashboard.Rows.Count, "B").End(xlUp).Row
Dim Answer As Long
Answer = WorksheetFunction.CountA(Range("B1:B" & CountLast))
With Dashboard
Total_Emails = CountLast - Answer
End With

Match Function in Specific Column Excel VBA

I'm trying to write a program in VBA for Excel 2011 that can search a column (which column that is is determined by another variable) for the number 1 so that it knows where to start an iteration.
Say that the number of the column is given by colnumvar. The only way I can think of is the Match function, which led me to write the following:
Dim rowvar As Integer
rowvar = WorksheetFunction.Match(1,Range(Cells(1,colnumvar),Cells(1000,colnumvar)),0)
This gave me an error, however. After playing around with it some more, I realized that it must not accept the Cells([row],[col]) way of doing it, but rather wants something like Range("A1:A100"). Unfortunately, I can't do it that way, since the program is figuring out what column to look in. Any help for figuring out how to get past this would be greatly appreciated!
What you mean to do is better served with Range.Find.
Dim rngtrg As Range, rngsrc As Range
Dim ws As Worksheet
Set ws = ActiveSheet
Set rngsrc = ws.Range(ws.Cells(1,colnumvar),ws.Cells(1000,colnumvar))
Set rngtrg = rngsrc.Find(1,...)
rowvar = rngtrg.Row
this easy function retreive the positoin of that you find
Function rowvar(ByRef c As Integer) As Integer
Dim keySrc As Integer
keySrc = 22 'wath you want to find
rowvar = WorksheetFunction.Match(keySrc, Range(Cells(1, c), Cells(1000, c)), 0)
End Function
use with rowvar(x)

Trying to find the number of rows in a particular sheet

Update: I figured out my error - the variable sheetRange needed the Sheets("Schedule"). added to it as well
Sorry for the inconvenience.
I have a relatively simple problem in that I am trying to use VBA to find the number of rows in a particular sheet. I am getting a pop up box that just says 400 and am not really sure where my syntax is off.
Sub PhxCheck()
Dim i As Integer, x As Integer, numofRows As Integer
Dim top As Range, bottom As Range, sheetRange As Range
Dim phxContract As String, contractID As String
Set top = Sheets("Schedule").Range("A3")
Set bottom = Sheets("Schedule").Range("A65536").End(xlUp)
Set sheetRange = Range(top, bottom)
numofRows = sheetRange.Rows.Count
Cells(30, 1).Value = numofRows
End Sub
The error happens when I add Sheets("Schedule"). to the top and bottom ranges.
Thanks for your help!
You can simplify your code a lot and avoid using redundant variables which will limit mistakes.
All you need is:
With Sheets("Schedule")
Cells(30, 1).Value = .Range("A3", .Cells(Rows.Count, "A").End(xlUp)).Rows.Count
End With
I understand you solved your problem yourself, but perhaps the above will help you or someone else searching for a similar problem.

Excel VBA Length-1 In a Range

I recently got into Excel macro development after a long time of not having the need to.
I have one column with two-hundred rows where each row has a value. I wrote a loop to iterate to each row value, read the current value and then write the value back minus the last character.
Here is some actual (and pseudo) code of what I wrote.
Dim theRow as Long
Dim totRow as Long
Dim fooStr as String
theRow = 2 'we begin on the second row of the colummn
totRow = 201 'there are 200 values
For theRow = 2 to totRow
fooStr = WorkSheets(DestSheet).Cells(theRow,"A").Formula 'read the cell value
fooStr = Left(fooStr,Len(fooStr)-1 'subtract the last character from the value
Cells(theRow,1).Value = fooStr 'write the value back
Next theRow
After I did some reading I learned that it is best practice to read and write values using a Range. Is it possible to rewrite what I am doing using a Range so it willl go faster.
Here is what I came up with so far.
Range("A2:A201").Value = Len(Range.Left("A2:A201").Value)-1
However, this doesn't work.
Any clues on how to do this if this is indeed possible?
Thanks for any tips.
If you want maximum performance (you don't need it for 200 rows, but...) you have to minimize the number of reads and writes (mostly writes) to ranges. That means reading the whole range into an array, manipulating the array, then writing it back to the range. That's one read and one write compared to 200 in a loop. Here's an example.
Sub RemoveLastChar()
Dim vaValues As Variant
Dim i As Long
vaValues = Sheet1.Range("A2").Resize(200).Value
For i = LBound(vaValues, 1) To UBound(vaValues, 1)
vaValues(i, 1) = Left$(vaValues(i, 1), Len(vaValues(i, 1)) - 1)
Next i
Sheet1.Range("A2").Resize(UBound(vaValues, 1), UBound(vaValues, 2)).Value = vaValues
End Sub
You could do something like
Sub StringTrim()
Dim xCell as Range
Range("A1:A201").Select
For Each xCell in Selection
xCell.Value = Left(xCell.Value, Len(xCell.Value) - 1)
Next
End Sub
I don't know what kind of speed improvements you are seeking, but that would also do the job.
You might know this already but putting Application.ScreenUpdating = False at the top of your code can speed it up significantly (unless you like to watch everything flash by as the script works). You should reset the value to True at the end of your code.