solve mismatch error for visual basic 6.0 - arrays

When I run this code it show a dialog box that says 'Mismatch Type' at line For i = 0 To UBound(arffArray). What is the problem with my code?
Public Function processFile()
Dim i, j, posRelation, temp, att, data, flag
Dim strRelation
Dim strAtt
Dim strData
strRelation = "#relation"
strAtt = "#attribute"
strData = "#data"
att = 0
data = 0
For i = 0 To UBound(arffArray)
If (InStr(arffArray(i), strRelation)) Then
temp = Replace(Mid(arffArray(i), 11, Len(arffArray(i))), "'", "")
RelationName = temp
ElseIf (InStr(arffArray(i), strAtt)) Then
flag = parseAtt(att, arffArray(i))
If (Not flag) Then
processFile = flag
Exit Function
End If
att = att + 1
ElseIf (InStr(arffArray(i), strData)) Then
data = readTheRest(i)
i = UBound(arffArray) 'end the loop
totalData = data
End If
Next
'get the list of class name
Dim tmpClassAttr
tmpClassAttr = attArray(1, UBound(attArray, 2))
For i = 0 To UBound(tmpClassAttr)
ReDim Preserve classArray(i)
classArray(i) = Trim(tmpClassAttr(i))
Next
processFile = True
End Function
'------------------------------------------------------------
'Function: parseAtt(num, attrData, ByVal m As MineKnow)
'require:
' >#num -> current attribute counter
' >#attrData -> current attribute declaration
'Raises: error if reading non numeric data/attribute
'Return: boolean parseAtt TRUE/FALSE, TRUE if parse successfully or otherwise
'Effect: parsing file content to:
' > attributes
'------------------------------------------------------------
Private Function parseAtt(num, attrData)
Dim temp, i, j, strAtt, temp2, pos, atVal
ReDim Preserve attArray(2, num)
'possible type of declarations
'#attribute outlook {sunny, rainy, overcast}
'#attribute outlook {sunny,rainy,overcast}
'attribute pos = 12
'get the attribute name first get the pos of "{"
pos = InStr(1, attrData, "{", 1)
If (pos = 0) Then
error = "---->Nominal attribute only." & vbCrLf & "---->" & attrData
parseAtt = False
Exit Function
Else
strAtt = Trim(Mid(attrData, 12, pos - 12))
atVal = Mid(attrData, pos + 1, Len(attrData) - (pos + 1))
atVal = Replace(atVal, "'", "")
atVal = Replace(atVal, "''", "")
atVal = Replace(atVal, "}", "")
atVal = Replace(atVal, " ", "")
temp = Split(atVal, ",")
attArray(0, num) = strAtt
attArray(1, num) = temp
parseAtt = True
End If
End Function

The biggest problem with your code is that you don't declare the type of your variables!!
Statements like
Dim i
will just declare the variable i as type Variant, which is definitely not what you want.
You actually want i to be declared as an Integer. You accomplish that by explicitly specifying the type at the point of declaration:
Dim i As Integer
Since the For loop is expecting an iterator index variable with type Integer, this should stop it from choking up that error.
Likewise, strings should always be declared explicitly as String types:
Dim strRelation As String
Note that when you declare multiple variables on a single line (which you probably shouldn't do, for clarity reasons), you need to make sure that you specify the type for each variable. It is not cumulative like other languages.
For example, this statement
Dim i, j, k As Integer
will declare only k as an Integer. i and j will be of type Variant, which is almost certainly (again) not what you wanted.
Instead, you need to write
Dim i As Integer, j As Integer, k As Integer
Of course, in this particular case, since VB 6 allows you to use variables with a lower bound that is not 0, it's probably best to code the loop like this:
Dim i As Integer
For i = LBound(arffArray) To UBound(arffArray)
' Do something with the array
Next i

Related

Populating array with items from another array throws TypeMismatch Error

for belows code the line vItemsNotInMaster(k) = vCheckItems(i) throws a type mismatch error once the array vItemsNotInMaster shall be populated. I am not sure why - as the caller sub and function array variables are all declared as Variants and types did not change according to the Locals Window.
I tried different data types but, this does throw other error messages.
Public Sub Testing()
Dim myArray1(1 To 4) As Variant
Dim myArray2(1 To 4) As Variant
Dim myArray3 As Variant
myArray1(1) = "one1"
myArray1(2) = "two3"
myArray1(3) = "three5"
myArray1(4) = "four7"
myArray2(1) = "one1"
myArray2(2) = "two3"
myArray2(3) = "different"
myArray2(4) = "four7"
myArray3 = Comparing_TwoArrays(myArray1, myArray2)
Stop
End Sub
Public Function Comparing_TwoArrays(ByVal vCheckItems As Variant, ByVal vMasterList As Variant) As Variant
Dim vItemsNotInMaster As Variant
Dim isMatch As Boolean
Dim i As Integer
Dim j As Integer
Dim k As Integer
ReDim vArray3(1 To UBound(vCheckItems, 1) + UBound(vMasterList, 1))
k = 1
For i = LBound(vCheckItems, 1) To UBound(vCheckItems, 1)
isMatch = False
For j = LBound(vMasterList, 1) To UBound(vMasterList, 1)
If vCheckItems(i) = vMasterList(j) Then
isMatch = True
Exit For
End If
Next j
If (isMatch = False) Then
vItemsNotInMaster(k) = vCheckItems(i) '---> Throws type mismatch
k = k + 1
End If
Next i
If (k > 1) Then
ReDim Preserve vArray3(1 To k - 1)
Else
vArray3 = Empty
End If
Comparing_TwoArrays = vArray3
End Function
Does someone has an idea?
Code Example credited to: https://bettersolutions.com/vba/arrays/comparing.htm
As I said in my comment, replacing vItemsNotInMaster(k) = vCheckItems(i) with vArray3(k) = vCheckItems(i) will solve the problem.
But if you need learning arrays manipulation, the next more compact code returns the same in less code lines number:
Public Sub Testing_()
Dim myArray1(1 To 4) As String
Dim myArray2(1 To 4) As String
Dim myArray3 As Variant
myArray1(1) = "one1"
myArray1(2) = "two2"
myArray1(3) = "three5"
myArray1(4) = "four7"
myArray2(1) = "one1"
myArray2(2) = "two3"
myArray2(3) = "different"
myArray2(4) = "four7"
myArray3 = Application.IfError(Application.match(myArray1, myArray2, 0), "x") 'it palces "x" when not a match...
Debug.Print Join(myArray3, "|") 'just to visually see the return...
'for a single case:
Debug.Print "(first) missing element: " & myArray1(Application.match("x", myArray3, 0)) 'it returns according to the first occurrence
'For more than one missing occurrence:
Dim i As Long
For i = 1 To UBound(myArray3)
If myArray3(i) = "x" Then
Debug.Print "Missing: " & myArray1(i)
End If
Next i
End Sub
To return occurrences independent of array elements position, it is also simpler to use Application.Match (with a single iteration). If interested, I can also post such a function...
As pointed out by #FunThomas the function does not return anything. Fix for type mismatch error is to Redim the vItemsNotInMaster array for each new item, while preserving the already populated values.
The vArray3 variable does not make sense and function should be rewritten as:
Public Function Comparing_TwoArrays(ByVal vCheckItems As Variant, ByVal vMasterList As Variant) As Variant
Dim vItemsNotInMaster()
Dim isMatch As Boolean
Dim i As Integer
Dim j As Integer
Dim k As Integer
k = 1
For i = LBound(vCheckItems, 1) To UBound(vCheckItems, 1)
isMatch = False
For j = LBound(vMasterList, 1) To UBound(vMasterList, 1)
If vCheckItems(i) = vMasterList(j) Then
isMatch = True
Exit For
End If
Next j
If (isMatch = False) Then
ReDim Preserve vItemsNotInMaster(1 To k)
vItemsNotInMaster(k) = vCheckItems(i) '---> Throws type mismatch
k = k + 1
End If
Next i
Comparing_TwoArrays = vItemsNotInMaster
End Function
Return Matching Array Elements
The function will return an array of the not matching elements from the check array in the master array.
If all elements are matching (are found in master), it will return an array whose upper limit is less than its lower limit.
Option Explicit
Public Sub Testing()
Dim myArray1(1 To 4) As Variant
Dim myArray2(1 To 4) As Variant
Dim myArray3 As Variant
myArray1(1) = "one1"
myArray1(2) = "two3"
myArray1(3) = "three5"
myArray1(4) = "four7"
myArray2(1) = "one1"
myArray2(2) = "two3"
myArray2(3) = "different"
myArray2(4) = "four7"
myArray3 = NotInMasterArray(myArray1, myArray2)
If LBound(myArray3) <= UBound(myArray3) Then
' Column
Debug.Print "Column" & vbLf & Join(myArray3, vbLf)
' Delimited row:
Debug.Print "Row" & vbLf & Join(myArray3, ",")
Else
Debug.Print "All elements from Check array found in Master array."
End If
Stop
End Sub
Public Function NotInMasterArray( _
arrCheck() As Variant, _
arrMaster() As Variant, _
Optional ByVal ResultLowerLimit As Variant) _
As Variant()
' Write the check array's limits to variables.
Dim cLB As Variant: cLB = LBound(arrCheck)
Dim cUB As Long: cUB = UBound(arrCheck)
' Determine the lower limit ('nLB') of the result array.
Dim nLB As Long
If IsMissing(ResultLowerLimit) Then ' use the check array's lower limit
nLB = cLB
Else ' use the given lower limit
nLB = ResultLowerLimit
End If
' Calculate the result array's upper limit.
Dim nUB As Long: nUB = cUB - cLB + nLB
' Define the initial result array ('arrNot') making it the same size
' as the check array (it is possibly too big; it is only of the correct size,
' if all check array's elements are not found in the master array).
Dim arrNot() As Variant: ReDim arrNot(nLB To nUB)
' Write the result array's lower limit decreased by 1 to the result
' array's limit counter variable (to first count and then write).
Dim n As Long: n = nLB - 1
Dim c As Long ' Check Array Limit Counter
' Loop through the elements of the check array.
For c = cLB To cUB
' Check if the current element is not found in the master array.
If IsError(Application.Match(arrCheck(c), arrMaster, 0)) Then
n = n + 1 ' count
arrNot(n) = arrCheck(c) ' write
'Else ' found in master; do nothing
End If
Next c
If n < nLB Then ' all found in master
arrNot = Array() ' i.e. UBound(arrNot) < LBound(arrNot)
Else ' not all are found in master
If n < nUB Then ' not all elements are not found...
ReDim Preserve arrNot(nLB To n) ' ... resize to 'n'
'Else ' all elements are not found; do nothing
End If
End If
' Assign the result array to the result of the function.
NotInMasterArray = arrNot
End Function

Type mismatch when converting from a Collection to an Array

I have a code where I'm adding last rows to collection which should be later transformed to an array and final step is to get last row with the least number of cells in it.
My current code is:
Dim lastc, lastc2, lastr, FindColNumber, FindColNumber2 as Long
Dim FindCol as Range
Dim col As New Collection
Dim CollectionToArray As Variant
Set FindCol = 1 'example
FindColNumber = FindCol.Column
lastc = FindColNumber + 1
Set FindCol2 = 5 'example
FindColNumber = FindCol2.Column
lastc2 = FindColNumber - 1
For R = lastc2 To lastc Step -1
lastc2 = R
col.Add Cells(ws.Rows.count, R).End(xlUp).Row
Next R
Debug.Print WorksheetFunction.Min(CollectionToArray(col))
Public Function CollectionToArray(myCol As Collection) As Variant
Dim result As Variant
Dim cnt As Long
ReDim result(myCol.count - 1)
For cnt = 0 To myCol.count - 1
result(cnt) = myCol(cnt + 1)
Next cnt
CollectionToArray = result
End Function
I am still getting Type Mismatch error and when hovering over CollectionToArray(Col)) I see "Object variable or With block variable not set".
Thank you.

VBA Compare 2 arrays, write unique values to cell with comma delimiter

I have a series of 2 cells in which values are separated by a comma delimiter.
Example
Cell D1 = 1,2,3,4,5,6,7,8,9,10
Cell O1 = 1,2,3,4,5,6
I want to first use the split function to pass the values to an Array and subsequently compare those 2 Arrays to find out the unique/not double values.
These values then i want to write to another cell as values with a comma delimiter.
Based on this answer
Comparing two Dimension array
and something I found about adding values to an Array i tried my luck with this code
Sub compare()
Dim cont As Long
Dim x As Long
Dim y As Long
Dim Source As Variant
Dim Comparison As Variant
Dim Target As Variant
With ThisWorkbook.Worksheets("Open items")
For cont = 1 To .Cells(Rows.Count, 4).End(xlUp).Row
Source = Split(.Range("D" & cont).Value, ",")
Comparison = Split(.Range("O" & cont).Value, ",")
For x = LBound(Source) To UBound(Source)
For y = LBound(Comparison) To UBound(Comparison)
If Source(x, y) = !Comparison(x, y) Then
Target(UBound(Target)) = Source(x, y).Value
Next
Next
Next cont
End Sub
But seem to be stuck.
Is this the correct way to add a value to the Array Target?
How do I get the Array into the cell?
The result in my example should be for Target to contain "7", "8", "9" , and "10" and should be shown in a cell in the way
7,8,9,10
Thank you for your help!
Some issues:
Rows.Count will look in the active sheet, not necessarily in the "Open items" sheet. So you need to add the dot: .Rows.Count
Source(x, y) will not work, since Source only has one dimension. In fact y has nothing to do with Source. A similar remark holds for Comparison.
= ! is not a valid comparison operator. You maybe intended <>.
Target is not defined, and Target(UBound(Target)) will always refer to the same location. Instead, you could append the result to a string variable immediately.
Furthermore, I would use a Collection object for fast look up, so that the algorithm is not O(n²), but O(n):
Sub Compare()
Dim cont As Long
Dim source As Variant
Dim comparison As Variant
Dim part As Variant
Dim parts As Collection
Dim result As String
With ThisWorkbook.Worksheets("Open items")
For cont = 1 To .Cells(.Rows.Count, 4).End(xlUp).Row
source = Split(.Range("D" & cont).Value, ",")
comparison = Split(.Range("O" & cont).Value, ",")
' Add the source items in a collection for faster look-up
Set parts = New Collection
For Each part In source
parts.Add Trim(part), Trim(part)
Next
' Remove the comparison items from the collection
For Each part In comparison
On Error Resume Next ' Ignore error when part is not in parts
parts.Remove Trim(part)
If Err Then parts.Add Trim(part), Trim(part) ' Add part if not yet in parts
On Error GoTo 0 ' Stop ignoring errors
Next
' Turn the remaining collection to comma-separated string
result = ""
For Each part In parts
result = result & ", " & part
Next
result = Mid(result, 3) ' Remove first comma and space
' Store the result somewhere, for example in the E column
.Range("E" & cont).Value = result
Next cont
End With
End Sub
Alternative for Sorted Lists
When your source and comparison lists are sorted in numerical order, and you need the target to maintain that sort order, you could use a tandem-kind of iteration, like this:
Sub Compare()
Dim cont As Long
Dim source As Variant
Dim comparison As Variant
Dim x As Long
Dim y As Long
Dim result As String
With ThisWorkbook.Worksheets("Open items")
For cont = 1 To .Cells(.Rows.Count, 4).End(xlUp).Row
source = Split(.Range("D" & cont).Value, ",")
comparison = Split(.Range("O" & cont).Value, ",")
x = LBound(source)
y = LBound(comparison)
result = ""
Do While x <= UBound(source) And y <= UBound(comparison)
If Val(source(x)) < Val(comparison(y)) Then
result = result & ", " & Trim(source(x))
x = x + 1
ElseIf Val(source(x)) > Val(comparison(y)) Then
result = result & ", " & Trim(comparison(y))
y = y + 1
Else
x = x + 1
y = y + 1
End If
Loop
' Flush the remainder of either source or comparison
Do While x <= UBound(source)
result = result & ", " & Trim(source(x))
x = x + 1
Loop
Do While y <= UBound(comparison)
result = result & ", " & Trim(comparison(y))
y = y + 1
Loop
result = Mid(result, 3) ' Remove first comma and space
' Store the result somewhere, for example in the E column
.Range("E" & cont).Value = result
Next cont
End With
End Sub
Try this small UDF():
Public Function unikue(BigString As String, LittleString As String) As String
Dim B As Variant, L As Variant, Barr, Larr
Dim Good As Boolean
Barr = Split(BigString, ",")
Larr = Split(LittleString, ",")
For Each B In Barr
Good = True
For Each L In Larr
If L = B Then Good = False
Next
If Good Then unikue = unikue & "," & B
Next B
If unikue <> "" Then unikue = Mid(unikue, 2)
End Function
Couple of things with this code
the variable Target() - You never tell code how big this array is or if you want to make it bigger - my full code below will grow for each match that is found
Source(x, y).Value - You dont need to use Value for arrays. you also do not need x and y as you are only reading in one column you only need source(x)
Where I have wrote MISSING in the full code - these lines where missing and would have caused you issues.
The purpose of Found is that for every time source(x) is found in Comparison(y) then Found is incremented. If it has never been incremented then we can assume that it is to be captured in target.
One other note is that you do not specify where you want to output Target to. so currently the target array does not go anywhere
Sub compare()
Dim cont As Long
Dim x As Long
Dim y As Long
Dim Source As Variant
Dim Comparison As Variant
Dim Target() As Variant
ReDim Target(1)
With ThisWorkbook.Worksheets("Open items")
For cont = 1 To .Cells(.Rows.Count, 4).End(xlUp).Row
Source = Split(.Range("D" & cont).Value, ",")
Comparison = Split(.Range("O" & cont).Value, ",")
For x = LBound(Source) To UBound(Source)
Found = 0
For y = LBound(Comparison) To UBound(Comparison)
If Source(x) = Comparison(y) Then
Found = Found + 1
'count if found
End If 'MISSING
Next
'if values are found dont add to target
If Found = 0 Then
Target(UBound(Target)) = Source(x)
ReDim Preserve Target(UBound(Target) + 1)
End If
Next
Next cont
End With 'MISSING
End Sub

My code is lying to me

I'm writing a code that checks if a word has multiple of the same letters in it, so I split each letter into an array and wrote this code. the "correctGuesses" variable is supposed to be the number of duplicate letters. The Array contains the strings ("H, E, L, L ,O").
Dim newCharArray() As Char = wordArray(rndNumber).ToCharArray
ReDim Preserve charToString_2(newCharArray.Length - 1)
Dim cBoolean As Boolean = False
For i As Integer = 0 To (newCharArray.Length - 1) Step 1
charToString_2(i) = newCharArray(i)
MsgBox(charToString_2(i))
Next
For j As Integer = 0 To (charToString_2.Length - 1) Step 1
For b As Integer = 0 To (charToString_2.Length - 1) Step 1
MsgBox("Is " & charToString_2(j) & " = " & charToString_2(b) & "?")
If j = b Then
MsgBox(j & " is equal to " & b & ", continuing.")
Exit For
End If
If CStr(charToString_2(b)) = CStr(charToString_2(b)) Then
MsgBox("Yes, +1")
correctGuesses += 1
charToString_2(b) = "Replaced"
cBoolean = True
End If
MsgBox("No, Continuing.")
Next
Next
The first if statement works, so whenever j = b, it exits and proceeds. But then the next loop, it checks if "E" is equal to "H", and it returns true! I have no idea why!
Your algorithm is almost there. You can tweak it a little.
Dim stringtoCheck As String = wordArray(rndNumber)
For j As Integer = 0 To (stringtoCheck.Length - 2)
For b As Integer = j+1 To (stringtoCheck.Length - 1)
If stringtoCheck.chars(b) = stringtoCheck.chars(j) Then
correctGuesses += 1
cBoolean = True
End If
Next
Next
This provides counts for the different characters in a string. Casing is shown.
Dim wordToCheck As String = "heLlo racecar" 'note L and l
Dim lettercounts As New Dictionary(Of Char, Integer)
For Each c As Char In wordToCheck ' .ToUpperInvariant '.ToLowerInvariant
If Not lettercounts.ContainsKey(c) Then
Dim ct As Integer = wordToCheck.Count(Function(ch) ch = c)
lettercounts.Add(c, ct)
End If
Next
'show the counts
For Each ltrct As KeyValuePair(Of Char, Integer) In lettercounts
Debug.WriteLine(String.Format("{0} {1}", ltrct.Key, ltrct.Value))
Next

Return Index of an Element in an Array Excel VBA

I have an array prLst that is a list of integers. The integers are not sorted, because their position in the array represents a particular column on a spreadsheet. I want to know how I find a particular integer in the array, and return its index.
There does not seem to be any resource on showing me how without turning the array into a range on the worksheet. This seems a bit complicated. Is this just not possible with VBA?
Dim pos, arr, val
arr=Array(1,2,4,5)
val = 4
pos=Application.Match(val, arr, False)
if not iserror(pos) then
Msgbox val & " is at position " & pos
else
Msgbox val & " not found!"
end if
Updated to show using Match (with .Index) to find a value in a dimension of a two-dimensional array:
Dim arr(1 To 10, 1 To 2)
Dim x
For x = 1 To 10
arr(x, 1) = x
arr(x, 2) = 11 - x
Next x
Debug.Print Application.Match(3, Application.Index(arr, 0, 1), 0)
Debug.Print Application.Match(3, Application.Index(arr, 0, 2), 0)
EDIT: it's worth illustrating here what #ARich pointed out in the comments - that using Index() to slice an array has horrible performance if you're doing it in a loop.
In testing (code below) the Index() approach is almost 2000-fold slower than using a nested loop.
Sub PerfTest()
Const VAL_TO_FIND As String = "R1800:C8"
Dim a(1 To 2000, 1 To 10)
Dim r As Long, c As Long, t
For r = 1 To 2000
For c = 1 To 10
a(r, c) = "R" & r & ":C" & c
Next c
Next r
t = Timer
Debug.Print FindLoop(a, VAL_TO_FIND), Timer - t
' >> 0.00781 sec
t = Timer
Debug.Print FindIndex(a, VAL_TO_FIND), Timer - t
' >> 14.18 sec
End Sub
Function FindLoop(arr, val) As Boolean
Dim r As Long, c As Long
For r = 1 To UBound(arr, 1)
For c = 1 To UBound(arr, 2)
If arr(r, c) = val Then
FindLoop = True
Exit Function
End If
Next c
Next r
End Function
Function FindIndex(arr, val)
Dim r As Long
For r = 1 To UBound(arr, 1)
If Not IsError(Application.Match(val, Application.Index(arr, r, 0), 0)) Then
FindIndex = True
Exit Function
End If
Next r
End Function
array of variants:
Public Function GetIndex(ByRef iaList() As Variant, ByVal value As Variant) As Long
Dim i As Long
For i = LBound(iaList) To UBound(iaList)
If value = iaList(i) Then
GetIndex = i
Exit For
End If
Next i
End Function
a fastest version for integers (as pref tested below)
Public Function GetIndex(ByRef iaList() As Integer, ByVal value As Integer) As Integer
Dim i As Integer
For i = LBound(iaList) To UBound(iaList)
If iaList(i) = value Then: GetIndex = i: Exit For:
Next i
End Function
' a snippet, replace myList and myValue to your varible names: (also have not tested)
a snippet, lets test the assumption the passing by reference as argument means something. (the answer is no) to use it replace myList and myValue to your variable names:
Dim found As Integer, foundi As Integer ' put only once
found = -1
For foundi = LBound(myList) To UBound(myList):
If myList(foundi) = myValue Then
found = foundi: Exit For
End If
Next
result = found
to prove the point I have made some benchmarks
here are the results:
---------------------------
Milliseconds
---------------------------
result0: 5 ' just empty loop
result1: 2702 ' function variant array
result2: 1498 ' function integer array
result3: 2511 ' snippet variant array
result4: 1508 ' snippet integer array
result5: 58493 ' excel function Application.Match on variant array
result6: 136128 ' excel function Application.Match on integer array
---------------------------
OK
---------------------------
a module:
Public Declare Function GetTickCount Lib "kernel32.dll" () As Long
#If VBA7 Then
Public Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As LongPtr) 'For 64 Bit Systems
#Else
Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) 'For 32 Bit Systems
#End If
Public Function GetIndex1(ByRef iaList() As Variant, ByVal value As Variant) As Long
Dim i As Long
For i = LBound(iaList) To UBound(iaList)
If value = iaList(i) Then
GetIndex = i
Exit For
End If
Next i
End Function
'maybe a faster variant for integers
Public Function GetIndex2(ByRef iaList() As Integer, ByVal value As Integer) As Integer
Dim i As Integer
For i = LBound(iaList) To UBound(iaList)
If iaList(i) = value Then: GetIndex = i: Exit For:
Next i
End Function
' a snippet, replace myList and myValue to your varible names: (also have not tested)
Public Sub test1()
Dim i As Integer
For i = LBound(iaList) To UBound(iaList)
If iaList(i) = value Then: GetIndex = i: Exit For:
Next i
End Sub
Sub testTimer()
Dim myList(500) As Variant, myValue As Variant
Dim myList2(500) As Integer, myValue2 As Integer
Dim n
For n = 1 To 500
myList(n) = n
Next
For n = 1 To 500
myList2(n) = n
Next
myValue = 100
myValue2 = 100
Dim oPM
Set oPM = New PerformanceMonitor
Dim result0 As Long
Dim result1 As Long
Dim result2 As Long
Dim result3 As Long
Dim result4 As Long
Dim result5 As Long
Dim result6 As Long
Dim t As Long
Dim a As Long
a = 0
Dim i
't = GetTickCount
oPM.StartCounter
For i = 1 To 1000000
Next
result0 = oPM.TimeElapsed() ' GetTickCount - t
a = 0
't = GetTickCount
oPM.StartCounter
For i = 1 To 1000000
a = GetIndex1(myList, myValue)
Next
result1 = oPM.TimeElapsed()
'result1 = GetTickCount - t
a = 0
't = GetTickCount
oPM.StartCounter
For i = 1 To 1000000
a = GetIndex2(myList2, myValue2)
Next
result2 = oPM.TimeElapsed()
'result2 = GetTickCount - t
a = 0
't = GetTickCount
oPM.StartCounter
Dim found As Integer, foundi As Integer ' put only once
For i = 1 To 1000000
found = -1
For foundi = LBound(myList) To UBound(myList):
If myList(foundi) = myValue Then
found = foundi: Exit For
End If
Next
a = found
Next
result3 = oPM.TimeElapsed()
'result3 = GetTickCount - t
a = 0
't = GetTickCount
oPM.StartCounter
For i = 1 To 1000000
found = -1
For foundi = LBound(myList2) To UBound(myList2):
If myList2(foundi) = myValue2 Then
found = foundi: Exit For
End If
Next
a = found
Next
result4 = oPM.TimeElapsed()
'result4 = GetTickCount - t
a = 0
't = GetTickCount
oPM.StartCounter
For i = 1 To 1000000
a = pos = Application.Match(myValue, myList, False)
Next
result5 = oPM.TimeElapsed()
'result5 = GetTickCount - t
a = 0
't = GetTickCount
oPM.StartCounter
For i = 1 To 1000000
a = pos = Application.Match(myValue2, myList2, False)
Next
result6 = oPM.TimeElapsed()
'result6 = GetTickCount - t
MsgBox "result0: " & result0 & vbCrLf & "result1: " & result1 & vbCrLf & "result2: " & result2 & vbCrLf & "result3: " & result3 & vbCrLf & "result4: " & result4 & vbCrLf & "result5: " & result5 & vbCrLf & "result6: " & result6, , "Milliseconds"
End Sub
a class named PerformanceMonitor
Option Explicit
Private Type LARGE_INTEGER
lowpart As Long
highpart As Long
End Type
Private Declare Function QueryPerformanceCounter Lib "kernel32" (lpPerformanceCount As LARGE_INTEGER) As Long
Private Declare Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As LARGE_INTEGER) As Long
Private m_CounterStart As LARGE_INTEGER
Private m_CounterEnd As LARGE_INTEGER
Private m_crFrequency As Double
Private Const TWO_32 = 4294967296# ' = 256# * 256# * 256# * 256#
Private Function LI2Double(LI As LARGE_INTEGER) As Double
Dim Low As Double
Low = LI.lowpart
If Low < 0 Then
Low = Low + TWO_32
End If
LI2Double = LI.highpart * TWO_32 + Low
End Function
Private Sub Class_Initialize()
Dim PerfFrequency As LARGE_INTEGER
QueryPerformanceFrequency PerfFrequency
m_crFrequency = LI2Double(PerfFrequency)
End Sub
Public Sub StartCounter()
QueryPerformanceCounter m_CounterStart
End Sub
Property Get TimeElapsed() As Double
Dim crStart As Double
Dim crStop As Double
QueryPerformanceCounter m_CounterEnd
crStart = LI2Double(m_CounterStart)
crStop = LI2Double(m_CounterEnd)
TimeElapsed = 1000# * (crStop - crStart) / m_crFrequency
End Property
Here's another way:
Option Explicit
' Just a little test stub.
Sub Tester()
Dim pList(500) As Integer
Dim i As Integer
For i = 0 To UBound(pList)
pList(i) = 500 - i
Next i
MsgBox "Value 18 is at array position " & FindInArray(pList, 18) & "."
MsgBox "Value 217 is at array position " & FindInArray(pList, 217) & "."
MsgBox "Value 1001 is at array position " & FindInArray(pList, 1001) & "."
End Sub
Function FindInArray(pList() As Integer, value As Integer)
Dim i As Integer
Dim FoundValueLocation As Integer
FoundValueLocation = -1
For i = 0 To UBound(pList)
If pList(i) = value Then
FoundValueLocation = i
Exit For
End If
Next i
FindInArray = FoundValueLocation
End Function
Is this what you are looking for?
public function GetIndex(byref iaList() as integer, byval iInteger as integer) as integer
dim i as integer
for i=lbound(ialist) to ubound(ialist)
if iInteger=ialist(i) then
GetIndex=i
exit for
end if
next i
end function
Taking care of whether the array starts at zero or one.
Also, when position 0 or 1 is returned by the function, making sure that the same is not confused as True or False returned by the function.
Function array_return_index(arr As Variant, val As Variant, Optional array_start_at_zero As Boolean = True) As Variant
Dim pos
pos = Application.Match(val, arr, False)
If Not IsError(pos) Then
If array_start_at_zero = True Then
pos = pos - 1
'initializing array at 0
End If
array_return_index = pos
Else
array_return_index = False
End If
End Function
Sub array_return_index_test()
Dim pos, arr, val
arr = Array(1, 2, 4, 5)
val = 1
'When array starts at zero
pos = array_return_index(arr, val)
If IsNumeric(pos) Then
MsgBox "Array starting at 0; Value found at : " & pos
Else
MsgBox "Not found"
End If
'When array starts at one
pos = array_return_index(arr, val, False)
If IsNumeric(pos) Then
MsgBox "Array starting at 1; Value found at : " & pos
Else
MsgBox "Not found"
End If
End Sub
'To return the position of an element within any-dimension array
'Returns 0 if the element is not in the array, and -1 if there is an error
Public Function posInArray(ByVal itemSearched As Variant, ByVal aArray As Variant) As Long
Dim pos As Long, item As Variant
posInArray = -1
If IsArray(aArray) Then
If not IsEmpty(aArray) Then
pos = 1
For Each item In aArray
If itemSearched = item Then
posInArray = pos
Exit Function
End If
pos = pos + 1
Next item
posInArray = 0
End If
End If
End Function
The only (& even though cumbersome but yet expedient / relatively quick) way I can do this, is to concatenate the any-dimensional array, and reduce it to 1 dimension, with "/[column number]//\|" as the delimiter.
& use a single-cell result multiple lookupall macro function on the this 1-d column.
& then index match to pull out the positions. (usuing multiple find match)
That way you get all matching occurrences of the element/string your looking for, in the original any-dimension array, and their positions. In one cell.
Wish I could write a macro / function for this entire process. It would save me more fuss.

Resources