I got the total number of columns, and tried to append it to string in such a way it is 1,2,3,4,5 depending on the number of columns.
Sub DeleteHighlightedRecords()
numofCol = ""
For i = 1 To lcol
numofCol = numofCol & "," & i
Next i
numofCol = Mid(numofCol, 2)
ThisWorkbook.Worksheets(1).Cells.RemoveDuplicates Columns:=Array(numofCol), Header:=xlNo
End Sub
The above code i have will match the combination i placed in Array(), and then remove the duplicates ya? Correct me if i am wrong, however I am getting application-defined error.
How may i set the dynamic numbers of columns into the Array()?
Array(1,2,3) is not the same as Array("1,2,3"). The first will produce an 3-element array containing 1,2 and 3, the second will produce an 1-element array containing the string "1,2,3".
To create an actual array we can do the following:
Dim numOfCol() As Variant 'normally I would choose Long instead of variant but that gave a type mismatch error
Dim i As Long 'always use "Option Explicit" at the top of your module!
ReDim numOfCol(0 To (lcol - 1)) 'has to be 0-based for RemoveDuplicates
For i = 0 To (lcol - 1)
numOfCol(i) = i + 1
Next i
Now as if using a Variant array instead of a Long array and using a 0-based array wasn't enough, RemoveDuplicates apparently also can't handle arguments passed as a reference to a variable instead of a value. To pass a variable as a value rather than a reference, encase it in parentheses. This causes the variable to be evaluated and then passed to the function.
ThisWorkbook.Worksheets(1).Cells.RemoveDuplicates Columns:=(numOfCol), Header:=xlNo
Related
I've looked up info with regards to column attributes. I'm trying to perform some insertions and copying of information within an array. The crux of my issue is that I want o nest some actions within a loop, so I need to index the column by a number not letter.
The first thing I do is find a starting point based upon a header name:
Dim EnvCondCol As String
Dim EnvCondColN As Long
Dim lColVVS As Integer
lColVVS = VET_VS.UsedRange.Columns.Count ' finds last column
For n = 1 To lColVVS
If UCase(VET_VS.Cells(3, n).Value) Like "*ENVIRONMENTAL CONDITION*" Then ' All Caps when using "like"
EnvCondCol = Split(VET_VS.Cells(3, n).Address, "$")(1)
EnvCondColN = Range(EnvCondCol & 1).Column
Exit For
End If
Next n
This works and when I watch EnvCondCol and EnvCondColN is can see EnvCondCol = "I" and EnvCondColN = "9"
Eventually, I want to insert a new column, and this line generates a syntax error:
VET_VS.Range(Columns.(EnvCondColN)).EntireColumn.Insert
When I watch EnvCondColN, it is a number, and I have tried changing the dim to other types, such as integer
Also elsewhere, I want to copy information from a cell into another cell from within a loop. This generates a syntax error.
VET_VS.Range(Columns.(EnvCondColN + i)).Copy VET_VS.Range(Columns.(EnvCondColN + j))
If I replace EnvCondColN with a value like 5, then this works. Example: VET_VS.Range(Columns.(5)).EntireColumn.Insert
Why isn't the variable working as a column reference??
Thank you all for looking!
change
VET_VS.Range(Columns.(EnvCondColN)).EntireColumn.Insert
to
VET_VS.Columns(EnvCondColN).EntireColumn.Insert
I have a "Datevarie" dynamic matrix which contains many dates.
At some point in the routine I have to extract from DateVarie the lowest value.
The problem is that when I use the Lbound function, I always return the value 1 instead of the date (for example "01/01/2018").
I think the data in the array is entered correctly as I debugged it step by step several times.
How can I resolve without having to report data on a sheet and order them? Do I have to use FOR ... NEXT? The dates can be 2-3 but also several tens
Type interventi
...
data as date
...
public Intervento as interventi
public rs1 as adodb.recordset
...
Sub TheSubWithProblem(...)
...
dim Datevarie() as date
..
redim preserve etc..
DateVarie(k)=format(RS1!DataI,"dd/mm/yyyy") '<<<< correct
...
Intervento.data=lbound(datevarie) '<<<< always return 1
...
The problem is that when I use the Lbound function, I always return the value 1 instead of the date (for example "01/01/2018").
LBOUND and UBOUND functions return the lower- and upper bounds of the array, not the lowest and highest values within the array.
Arrays in VBA are base-0 by default, so an initialized array should typically have LBound of 0.
If you want to get the lowest or highest value, then you need to implement your own algorithm to do so (e.g., a for/next loop), or if this is a single-dimensional array we can potentially make use of an ArrayList object which has (among other things) a Sort method:
Set d = CreateObject("System.Collections.ArrayList")
Dim dateVarie As Variant
Dim i As Long, m As Long, day As Long
For i = 1 To 100
m = Application.WorksheetFunction.RandBetween(1, 12)
day = Application.WorksheetFunction.RandBetween(1, 30)
d.Add (DateValue(DateSerial(2018, m, day)))
Next
'Preserve your un-sorted array, if needed:
ReDim dateVarie(d.Count - 1)
dateVarie = d.ToArray()
Msgbox "The first value is: " & dateVarie(0)
d.Sort ' Sorts the arraylist:
MsgBox "The lowest value is: " & (d(0))
Arrays start at 0. This is why the below returns 0:
Sub TestMe()
Dim datevarie(2) As Date
Debug.Print LBound(datevarie)
End Sub
And it does not matter, whether you put values in the array or not.
If you want an array to start at 1, in VBA write Option Base 1 and make sure that noone sees the code, because you may have problems with your colleagues/peers:
Option Explicit
Option Base 1
Sub TestMe()
Dim datevarie(2) As Date
Debug.Print LBound(datevarie)
End Sub
I am running into some issues while using VBA its 'Filter' function. I am trying to use multiple subsequent filters to step by step reduce the array down the contain the value I need. It however seems that only the first element that matches the 'Match' value is returned and not the subsequent ones?
To given an example, when running the code below, the second 'debug call' return '1' but it should return '2'
Function FilterAnArray()
Dim names As Variant
names = Array("Ann Smith", "Barry Jones", "John Smith", "Stephen Brown", "Wilfred Cross")
Debug.Print UBound(names)
Dim smithNames As Variant
smithNames = Filter(names, "Smith")
Debug.Print UBound(smithNames)
End Function
Version information e.t.c.
I am running Excel 2016, version 16.0.8730.2046 - 64-bit.
Any help with this issue is much appreciated!
It is working quite ok. It is returning 1, because you have two Smith's:
And the Upper bound of smithNames is 1, because it arrays are 0-based. If you want the count of the array elements, and you do not like the UBound+1, you may use a worksheet function:
Debug.Print WorksheetFunction.CountA(smithNames)
Strongly not adviseable option:
You may consider writing Option Base 1 on the top of the module. Then the arrays will be 1-based and will be the way you expect it. In your example you see why Option Base 1 is not advisable. If you have it, Names will be 1 based and smithNames will be 0 based. This is because of the different way the arrays are assigned.
Ubound gives the uppfer bound. As you use 0-based arrays you get a result of 4 for 5 entries and a result of 1 for 2 entries.
If you want to use 1-based array without explicitly dimensionen each array use Option Base 1 at the beginning of you Module.
How about checking how many results you ought to get and then printing them, such as:
Sub foo()
Dim val As Variant
Dim names As Variant
Dim post As Variant
names = Array("Ann Smith", "Barry Jones", "John Smith", "Stephen Brown", "Wilfred Cross")
Debug.Print UBound(names)
Dim smithNames As Variant
smithNames = Filter(names, "Smith")
pos = Application.Match(smithNames, names, False) 'find how many values match "Smith"
If Not IsError(pos) Then
For x = LBound(pos) To UBound(pos)
Debug.Print pos(x)
Next x
Else
MsgBox val & " not found!"
End If
End Sub
How do I get the length of character between beginning with space and ending with * Here is the image. Column B shows the total len before dasher(-) and my code
Sub xn()
Dim x As Integer
x = 1
If Worksheet("Sheet1").Range("A"& x).len(Right," ") Or _
Worksheet("Sheet1").Range("A"&x)len(Left,"-") Then
len(totallen)
End If
x = x + 1
End Sub
The code posted has multiple issues:
Worksheet is not a valid object - you need to use Worksheets.
.len is not a property of a Range object.
Even in .len was a property of a Range, you would need a
de-reference operator (aka '.') in here: Range("A"&x)len(Left,"-")
If you intend to use the function Len(), it only takes one argument.
You apparently are trying to loop, but you need to use either a For
or For Each loop - it won't loop automatically when you increment x
at the bottom of the sub.
Right is a function, but you're calling it without arguments and they are not optional.
Similarly, Left is a function, but you're also calling it without
the required arguments.
totallen is not declared anywhere, so Len(totallen) will assume
that totallen is a Variant (default for undeclared variables), then
cast it to a String, and then always return 0 because it has never
been given a value.
Anything else I may have missed.
The solution is to use the InStr function. It returns the location in a string of a given sub-string.
Sub xn()
Dim x As Long
Dim sheet As Worksheet
Set sheet = ActiveWorkbook.Worksheets("Sheet1")
For x = 1 To sheet.Range("A" & sheet.Rows.Count).End(xlUp).Row
sheet.Cells(x, 2) = InStr(1, sheet.Cells(x, 1), "-") - 1
Next x
End Sub
I'd also recommend taking a look at the MSDN article on Looping Through a Range of Cells (2003 vintage, but still valid), and Error Finding Last Used cell In VBA.
I am using VLookup function which looks up multiple values which are present in the column. This works very well but just takes a lot of time as I have 100,000 rows in the Excel sheet.
Is there any way to quicken this code?
The code basically looks up a particular value in a column and gets the offset. The difference between simple VLookup and this is that in case there are multiple rows with the same lookup value then it gets all the elements.
Function VLookupAll(ByVal lookup_value As String, _
ByVal lookup_column As Range, _
ByVal return_value_column As Long, _
Optional seperator As String = ", ") As String
Dim i As Long
Dim result As String
For i = 1 To lookup_column.Rows.Count
If Len(lookup_column(i, 1).Text) <> 0 Then
If lookup_column(i, 1).Text = lookup_value Then
result = result & (lookup_column(i).Offset(0, return_value_column).Text & seperator)
End If
End If
Next
If Len(result) <> 0 Then
result = Left(result, Len(result) - Len(seperator))
End If
VLookupAll = result
End Function
This is about 20-30x faster than a simple loop (tested over a column of 20k values, with 3 matches to the value being searched).
'rng: a single-column range to search for matches
'val: the value to match on
'col: offset from match in rng to concatenate values from (similar
' to the matching VLOOKUP argument)
Function MultiLookup(rng As Range, val As String, col As Long)
Dim i As Long, v, s
Dim r As Long
r = rng.Cells.Count
v = Application.Match(val, rng, 0)
s = ""
Do While Not IsError(v)
s = s & IIf(s <> "", ",", "") & rng.Cells(v).Offset(0, col - 1).Value
r = r - v
Set rng = rng.Offset(v, 0).Resize(r, 1)
v = Application.Match(val, rng, 0)
Loop
MultiLookup = s
End Function
http://www.excelhero.com/blog/2011/03/the-imposing-index.html says "Excel INDEX MATCH is significantly quicker than VLOOKUP"
You could try doing a Range.Find to see if the value exists at all in lookup column before proceeding. You are looping through every item in lookup column only to find it isn't there. If it were me, I would do a Range.find to see if lookup value is in lookup_column. If it is then you could do a countif to see how many occurrences there are...if there is only one occurrence, use plain old VLookup...and only fall back into your process if there is more than one occurrence.....may work....of course if Find fails, bail out of the function.
Another option is to load the lookup_column into any array...and process the array rather than the range.mnthat can sometimes help.
Summary:
Concate the values and do a vlookup on that new value.
For me I needed to have a formula and not a function to look up by 2 values. VLOOKUP could only work by a single value from what I've seen, so my solution was to concatenate the 2 values for a single primary key.
In my raw data tab I added a column called Lookup that simply concatenated the ID column with the Timestamp columns I had.
Then in my comparison tab I had
=VLOOKUP(CONCATENATE(A4, $F$1),'Historical Data'!$A:$G,3,FALSE)
Which took the ID column, concatenated with my lookup date at $F$1, and vlookup'ed into my data tab (Historical Data).