I have a Variant in VB6 with thousands of Strings.
I also have an array of fixed length.
I need to compare the contents of each and add the ones that match to a list.
if array(i) = variant(1,i) then
'add to list
End if
I cannot figure out how to iterate over both properly in order to compare, as the method I use to iterate over the Variant() stops after going through each item. So it never checks to see if it any item is equal to i+1 in the array.
Private Sub dp_Click()
Dim fArray
fArray = Array("a", "b", "c")
LstAPens.ListItems.Clear
LstUPens.ListItems.Clear
For x = 0 To UBound(fArray)
Dim i As Long, m As Integer
'Do Until batcharray(0, i) = "End"
' tmpArray(i) = UCase(batcharray(1, i))
'Loop
Do Until batcharray(0, i) = "End"
If (InStr(1, UCase(batcharray(1, i)), UCase(fArray(x))) > 0) Then
LstAPens.ListItems.Add
With LstAPens.ListItems(m + 1)
.SubItems(1) = batcharray(1, i) 'Tagname
End With
m = m + 1
End If
i=i+1
Loop
Next x
End Sub
I tried to convert the Variant to an array but it did not work.
The only item that is found is the first one in the array, then the Variant is no longer iterated over as it reached the end.
How can I iterate over the Variant called batchArray in this example, and compare it to the contents of an array?
This really isn't a Variant problem, it's just a looping/control variable issue.
Even though you have your DIM statement inside your main loop, VB does not treat that as a "redeclaration" and reset/reinitialize its value before your UNTIL loop. As a result, 'i' will increment to 1 and then retain its value between iterations of your outer loop, thus remaining stuck on the single value in batchArray and the iteration ceases.
Move the declaration outside the loop, reset it to 0 before the UNTIL loop, and see if that solves your problem:
Dim i as Long
For x = 0 To UBound(fArray)
Dim m As Integer
i = 0
Do Until batcharray(0, i) = "End"
If (InStr(1, UCase(batcharray(1, i)), UCase(fArray(x))) > 0) Then
LstAPens.ListItems.Add
With LstAPens.ListItems(m + 1)
.SubItems(1) = batcharray(1, i) 'Tagname
End With
m = m + 1
End If
i=i+1
Loop
Next x
Related
I have an array with over 130 elements, out of those elements I only want specific elements. Those elements I have been able to specify with an if statement and an Instr function. However, I am stuck when figuring out how to those values from main array into a different array. The issue is that I don't know how many values will actually fit the requirements and so the second array I can't define before the values are counted.
How would I transfer certain values that fit the Instr function from one array to the other array.
Current code -
For v = 0 To UBound(NViews)
ViewNames = NViews(v)
If InStr(ViewNames, "Triage Folder") Then
ReDim TriageNames(0 To p)
TriageNames(p) = NViews(v)
p = p + 1
End If
Next
Updated Code**
p = 1
ReDim TriageNames(0 To p)
For v = 0 To UBound(NViews)
ViewNames = NViews(v)
If InStr(ViewNames, "Triage Folder") Then
TriageNames(p) = NViews(v)
p = p + 1
ReDim Preserve TriageNames(0 To p)
End If
Next
Make TriageNames the same size as NViews, then use ReDim Preserve, after you populated TriageNames completely:
Dim TriageNames As Variant
ReDim TriageNames(0 to Ubound(NViews))
For v = 0 To Ubound(NViews)
If InStr(NViews(v), "Triage Folder") > 0 Then
Dim p As Long
TriageNames(p) = NViews(v)
p = p + 1
End If
Next
If p > 0 Then
ReDim Preserve TriageNames(0 to p - 1)
End If
I am struggling with a basic problem in VBA and would appreciate some help. I want to define a function which returns an array from a range without blanks, as shown below:
So when I call the function in the European Option cell, the function should return an array without any blanks, like on the right hand side.
This is the code I have so far:
Function portfolioX(N)
Dim MyArray(3)
Dim i As Integer
counter = 1
For i = 1 To N
If IsEmpty(i) Then
Next i
Else
portfolio = MyArray
MyArray (counter)
counter = counter + 1
Next i
End If
End Function
I am a newbie to VBA, so this could be completely wrong. Thanks!
If statement and loop are blocks of code. You can not interlace blocks of code.
Function portfolioX(N)
For i = 1 To N ' Block 1 starts
If IsEmpty(i) Then ' Block 2 starts
Next i 'Block 1 can't loop back because Block 2 has't closed
Else
portfolio = MyArray
MyArray (counter)
counter = counter + 1
Next i 'Block 1 can't loop back because Block 2 has't closed
End If ' Block 2
End Function
When coding it is code practice to write the complete loop structure then fill in the inner code.
I would write the For loop first
For i = 1 to N
next i
Next comes the If block
For i = 1 To N
If IsEmpty(i) Then
End If
Next i
And finally
Function portfolioX(N)
Dim MyArray(3)
Dim i As Integer
counter = 1
For i = 1 To N ' Block 1 Starts
If IsEmpty(i) Then Block 2 Starts
portfolio = MyArray
MyArray (counter)
counter = counter + 1
End If ' Block 2 Closes
Next i 'If the Loop Condition is meet, Block 1 Closes, else i is incremented and the loop starts over
End Function
Given what you are asking for, I've written a quick sub that will take whatever range you have highlighted and paste the values with the blank cells removed at the end of the row. Hopefully this can give you a start towards what you are hoping to accomplish.
Sub RemoveBlanks()
Dim OriginalRange As Range, WorkCell As Range, PasteCol As Integer
Set OriginalRange = Selection.Rows(1) 'Ensures only one row of data is selected
PasteCol = Range(Cells(OriginalRange.Row, ActiveSheet.UsedRange.Columns.Count + 2).Address).End(xlToLeft)
For Each WorkCell In OriginalRange
If Not IsEmpty(WorkCell) Then
Cells(OriginalRange.Row, PasteCol).Value = WorkCell.Value
PasteCol = PasteCol + 1
Next WorkCell
End Sub
Based on your question and comments in that thread, I understand that you wish to take a given range (supplied to the procedure) and print all non-empty values to some range starting on the same row in column R (the 18th column).
In a comment, you supply the ranges A1:A13 and A18:A21, but those do not match with your screenshot. I assume you meant row 1 (or some arbitrary row), columns 1 to 13 and columns 18 to 21.
Here is a solution to that problem:
Sub arrayPaster(rng As Range)
Dim s() As Variant, r() As Variant, j As Integer
ReDim r(1 To 1, 1 To 1)
s = rng.Value
j = 1
For i = 1 To UBound(s, 2)
If s(1, i) <> "" Then
ReDim Preserve r(1 To 1, 1 To j)
r(1, j) = s(1, i)
j = j + 1
End If
Next i
Range("R" & rng.Row).Resize(1, UBound(r, 2)).Value = r
End Sub
I have found lots of methods to remove duplicates of a 1D array but could not find a 2D example.
In addition to that, I wonder if the fuction can "leave" an instance of the duplicate item instead of removing them all.
Is it possible to do it?
Example:
Sub Tests()
Dim Example()
Example(0,0) = "Apple"
Example(1,0) = "Apple"
Example(0,1) = "Pear"
Example(1,1) = "Orange"
End Sub
Remaining items would be: Apple, Pear and Orange
This is how I like to do it, using a separate array to hold the unique items. This prevents your loops from having to cycle through non unique items when trying to test them.
Sub Test()
Dim Example(1, 1) As String
Dim NoDups() As String
Dim I, II, III As Long
ReDim NoDups(UBound(Example, 1) * UBound(Example, 2))
For I = 0 To UBound(Example, 1)
For II = 0 To UBound(Example, 2)
For III = 0 To UBound(NoDups)
If NoDups(III) = Example(I, II) Then
Exit For
ElseIf NoDups(III) = "" Then
NoDups(III) = Example(I, II)
Exit For
End If
Next
Next
Next
End Sub
To work through a 2D array, do as you would with a 1D array, but with a 'width' loop inside of a 'height' loop.
ie:
for a = 1 to number_of_elements_in_first_dimension
for y = 1 to number_of_elements_in_second_dimension
initial_comparison_string = array(a,b)
for x = a to number_of_elements_in_first_dimension
for y = b + 1 to number_of_elements_in_second_dimension
if Initial_comparison_string = array(x,y) then array(x,y) = ""
next y
next x
next b
next a
This will run fairly slowly with a very large 2D array, but I think you'd have to do 2 nested loops like this to take each value and compare it against each value which appears later.
I have input array {{1,4}, {1,3}, {1,4,7}}
Dim array1() As Long
ReDim array1(3, 3)
array1(1, 1) = 1
array1(1, 2) = 4
array1(2, 1) = 1
array1(2, 2) = 3
array1(3, 1) = 1
array1(3, 2) = 4
array1(3, 3) = 7
I would like to have output array (which is length of each subarray) {2,2,3}
I am thinking to use for loop as following
Dim i As Long
i = UBound(array1, 1)
Dim outputarray() As Long
ReDim outputarray(i) As Long
For j = 1 To i
outputarray(i) = UBound(array1(i), 2) 'ERROR APPEAR
Next j
i added Option Base 1
The length of each subarray stay the same, its always 3 in your case. Your redim has defined the number you want to get. So there's no point trying to retrieve it like you want to do.
The fact that you don't move any values in
array1(1, 3)
array1(2, 3)
doesn't affect the dimensions of your array. You'll find values in these what-you-think-empty array's cells, and it will be 0 because you declared your array as long. If you had declared it as string, you would find a blank string in them, neither null nor "nothing".
You have input array {{1,4,0}, {1,3,0}, {1,4,7}}
If your aim is to find which elements of your array are 0 because you didn't moved anything in them, that's another story not related to the length of your array.
I agree with Thomas' answer above.
If you do find yourself interested in knowing the number of populated array values in the array, you might consider the following:
Start with the first row, and the right-most value in that array. So your for loop would actually be two loops - one to go through the first dimension, and one to go through the second dimension.
Move left through the array until you run into a non-zero value. Keep a count of the total values that are zero. When you run into a non-zero value, subtract the total zero values from the second dimension of the array. This will give you the "length" that you were looking for before.
So for example:
Dim i As int
Dim j As int
Dim h As int
Dim w As int
h = UBound(array1, 1)
w = UBound(array1, 2)
Dim rowVals as int
Dim arrVals as int
For i = 0 To h
rowVals = 0
For j = w to 0 Step -1
if array1(i,j) = 0 Then
exit for
else
rowVals = rowVals + 1
end if
Next
arrVals = arrVals + rowVals
Next
Here's what I'm trying to do:
Suppose that you have a dynamic array whose dimensions can be from 0x6 up to 10x6 (meaning we can have rows anywhere from 0 to 10, but columns are always 6). I have been desperately trying to create a function (and then bind it to a macro) that will use as argument this first array, and will create a second array as output, whose elements will be the returns of the first array. For example, if we have the simple case of 1x6, then the output array's elements are five and in each case are given by the formula (x_i+1 - x_i)/x_i, i=1, 2, ..., 6. Additionally, the function must be able to bypass any missing values from the input array and ignore the corresponding non-existent return values. The entire thing must be done in VBA script.
It's been two days since I have been searching frantically for some help, but the problem is that I have no idea whatsoever about programming in VBA (I usually use other languages like MATLAB or Mathematica) so this is extremely hard for me. Any solutions that I have found I wasn't able to put together and achieve my goal. Any help is greatly appreciated.
Because you provided no code, I cannot determine exactly what you want to do, but here is an example of passing an array and returning an array that you should be able to extrapolate.
Edit: Just for fun, updated this to work for up to 3 dimensional arrays.
Public Sub Test()
'Defines testArray as Variant 0 to 10
Dim testArray(0 To 1, 0 To 6) As Long
Dim returnArray() As Long
Dim i As Long
Debug.Print UBound(testArray, 2)
'Populates testArray with Longs
For i = 0 To UBound(testArray, 1)
For j = 0 To UBound(testArray, 2)
testArray(i, j) = (i + j) * 2
Next
Next
'Passes testArray and returns ParseArray
returnArray = addOne(testArray)
End Sub
Public Function addOne(arrValues() As Long) As Variant
Dim arrCopy() As Long
Dim dimensionNum As Long, ErrorCheck As Long
On Error Resume Next
For dimensionNum = 1 To 60000
ErrorCheck = LBound(arrValues, dimensionNum)
If Err.Number <> 0 Then
dimensionNum = dimensionNum - 1
Exit For
End If
Next
Dim i As Long, j As Long, k As Long
'Copies passed array to avoid updating passed array directly
arrCopy = arrValues
'Adds 1 to each element of the array.
If dimensionNum = 1 Then
For i = LBound(arrCopy) To UBound(arrCopy)
arrCopy(i) = arrCopy(i) + 1
Next
ElseIf dimensionNum = 2 Then
For i = LBound(arrCopy) To UBound(arrCopy)
For j = LBound(arrCopy, 2) To UBound(arrCopy, 2)
arrCopy(i, j) = arrCopy(i, j) + 1
Next
Next
ElseIf dimensionNum = 3 Then
For i = LBound(arrCopy) To UBound(arrCopy)
For j = LBound(arrCopy, 2) To UBound(arrCopy, 2)
For k = LBound(arrCopy, 3) To UBound(arrCopy, 3)
arrCopy(i, j, k) = arrCopy(i, j, k) + 1
Next
Next
Next
Else
MsgBox "Add function only works for three dimensions or fewer arrays"
End If
addOne = arrCopy
End Function