Find index on array using content - arrays

I have create an array of integers.
Dim EnemyLevel() as Integer = {1,2,2,3}
Let's say I wanted to get the position of every item that included '2', that'd be EnemyLevel(1) and EnemyLevel(2), what's the function to do that?
I'm supossed to use Array.IndexOf(EnemyLevel(),2) but how do I store the results?

You run the array in a For Loop. And check if any of the indices contain '2'
Array1 = Array(1,2,2,4)
For i=0 to UBound(Array1)
If Array1(i) = 2 Then
msgbox i
End If
Next

Related

Is there a way to transfer all values from one array to another, then erase the original array?

I'm running into a problem with a block of code I'm trying to develop at my job. Essentially, I'm creating a userform in excel where folks will enter data for railcars as they get loaded at a certain location (we'll call these "spot 1, spot 2, spot 3, etc.").
Sometimes they'll have to move that car to a different spot, in which case I want them to be able to keep all the information on the railcar from the first/original entry, and then erase the data from the original spot once that's done.
To accomplish this in a more streamlined fashion, I've established arrays for each of the 5 spots that reference all the cells they're entering data into on the userform:
Dim spot1information(14)
spot1information(0) = UserForm.ProductType1.Value
spot1information(1) = UserForm.ProductID1.Value
spot1information(2) = UserForm.BatchID1.Value
etc....
Dim spot2information(14)
spot2information(0) = UserForm.ProductType2.Value
spot2information(1) = UserForm.ProductID2.Value
spot2information(2) = UserForm.BatchID2.Value
etc....
And so forth for all five spots. I don't know if this makes things more difficult, but note that these array values aren't all of the same type. For instance, index (0) will be a string, but index (10) is a DATETIME and index (12) is defined as Long.
So say that they are moving a car from spot 1 to spot 2. In short, I want the code to do the following:
Replace the values of indices 0 - 6 in spot2information (which is currently empty) with the values of indices 0 - 6 in spot1information (which the user has filled on the userform).
I'm only interested in carrying over indices 0-6 because they contain the pertinent railcar information
Empty every value of spot1information to ""
To accomplish this, I tried the following code and a few variations thereof:
If OriginalSpot.Value = 1 Then
If DestinationSpot.Value = 2 Then
For i = 0 to 6
spot2information(i) = spot1information(i)
Next
For Each i in spot1information
spot1information(i) = ""
Next
End If
End If
However, this keeps coming up with a type mismatch. I figure because the data in the spot2information array is empty, and the data in the spot1information array is not, but I'm not entirely sure of a way around this.
Update: I did what was suggested below and replaced: spot1information(i) = "" with Erase spot1information
The code now essentially works! The values of array "spot2information" are now the former values of "spot1information", with "spot1information" now empty.
The 2D array suggested below also works like a charm. New problem I've been facing is that array values are updating, but the userform isn't. (note: in the future I'll be posting this type of thing as a separate question, my apologies!)
Easier to manage this as a 2D array:
Sub Tester()
Dim spots(1 To 5, 0 To 14), n As Long, i As Long
'fill your spot arrays from the form....
For n = 1 To 5
spots(n, 0) = UserForm.Controls("ProductType" & n).Value
spots(n, 1) = UserForm.Controls("ProductID" & n).Value
spots(n, 2) = UserForm.Controls("BatchID" & n).Value
'etc etc
Next n
'swap a spot with another
Debug.Print spots(2, 1), spots(3, 1)
SwapSpots spots:=spots, fromSpot:=2, toSpot:=3
Debug.Print spots(2, 1), spots(3, 1)
End Sub
Sub SwapSpots(spots, fromSpot As Long, toSpot As Long)
Dim n As Long
For n = 0 To 6
spots(toSpot, n) = spots(fromSpot, n)
spots(fromSpot, n) = Empty 'empty the source slot value
Next n
End Sub
Assuming the DataType of the arrays is the same by Index i.e. index(0) is string for all spots, Index(2) is long for all spots, and so on.
If that is the case then this part should not produce any error:
For i = 0 to 6
spot2information(i) = spot1information(i)
Next
The error should be happening in this part more precisely in the line marked with #
For Each i in spot1information
spot1information(i) = "" '#
Next
and the reason for the error it seems to be that trying to assign a string value "" to a numeric type, given the "mismatch" error.
Using For Each i in spot1information indicates that you want to "Initiate" or Erase the entire array, therefore I suggest to use this line instead of the For…Next method.
Erase spot1information
In regards this:
But I've now run into a new problem, where the values on the userform haven't updated to reflect the new values stored in the array. Do I need to somehow "refresh" the userform?
You just updated the arrays, then you need to run the procedures used to update the values of the objects affected by both arrays in the UserForm.

For Each through single rank of multidimensional array

I have a 2D array - aArray(1,variable) and want to know how I can For Each through the first rank of the array, ie only read aArray(0 , variable)
This is more for self educational purposes as to how if possible it can be done. I can do it with a for loop:
Dim a As Integer: For a = 0 to ?
Range("A1").Value = aArray(0,a)
Next a
But was interested in using the For Each loop. So far I've got
Dim a As Variant: For Each S In aArray
Range("A1").Value = S
Next a
But it iterates through all the array (0,0) (1,0) (0,1) (1,1) Etc...
You can't do that. You'd have to output the first rank into a new array, and then iterate through that.
There's no good reason to use For Each anyway since it's slower - see: https://support.microsoft.com/en-us/kb/129931

Getting the index of item in an array VBA

I am trying to get the index of the item in an array VBA, but I have issue getting it.
Const NoOfVol As Integer = 5
Dim vol(NoOfVol) As Integer
For Index = 1 To NoOfVol
vol(Index) = Cells(15 + Index, 8).Value
Next
The array looks like this: (-2500,-1250,0,1250,2500). I am calling the function this way.
Function Find(ByVal Value As Variant, arr As Variant) As Integer
Find = Application.Match(Value, arr, False)
End Function
posOfVol = Find(-1250, vol)
But the posOfVol = 3, when it should be 2. Not sure where my error is. Need some guidance on this.
Your array is actually effectively declared as:
Dim vol(0 to NoOfVol) As Integer
unless you have an Option Base 1 statement. Since your loop goes from 1 to 5, you never populate the first element of the array and it retains its default value of 0. Therefore your array is actually:
(0,-2500,-1250,0,1250,2500)
and since you are looking for an exact match, -1250 is found at the third position.

changing size of 2D array with vba

I always have trouble with Arrays which is why I usually avoid them but this time I'm trying to get my head round them
I'm trying to change the size of my Global Array inside vba
I have declared it using Public UseArr() As String
Now I've written a function that searches an SQL table and returns user information as a record set.
I want to take this record set and put it into my Global Array
This is the bit of code I've written for populating it
a = 0
If Not Not UseArr Then
For i = 0 To UBound(UseArr)
If StrComp(UseArr(i, 0), rs("Alias")) = 0 Then a = 1
Next i
b = i
Else
b = 0
End If
If a = 0 Then
ReDim Preserve UseArr(0 To b, 0 To 10)
With rs
If Not .BOF And Not .EOF Then
For j = 0 To 10
If Not rs(j) = "" Then
UseArr(b, j) = rs(j)
Else
UseArr(b, j) = "Null"
End If
Next j
End If
End With
End If
The idea being if the user is already in there it doesn't populate, and if not it populates.
It works fine for initialising the Array however when I go to put in a second user it throws a resize error.
Can anyone help?
Thanks in advance
Tom
Update with Dictionary Attempt
If UseList Is Nothing Then
Set UseList = New Dictionary
MsgBox "Created New"
End If
If UseList.Exists(rs("Alias")) Then
Dim temp()
For i = 0 To 10
temp(i) = rs(i + 1)
Next i
With UseList
.Add Key:=rs("Alias"), Item:=temp
End With
End If
Debug.Print UseList
You can only Redim Preserve the last dimension of a multi-dimensional array - see here. Have you considered using a Collection or Dictionary instead?
edit: using the code you've posted above, here's how you would display element 4 from the array associated with the key "tom"
MsgBox UseList("tom")(4)
or equivalently
MsgBox UseList.Item("tom")(4)
Here you have some explanation about how a Dictionary object works and some of its attributes and functions.
I think it's the best to reach your goal because they are so easy to use, fast and efficient.
First you have to import the mscorlib.dll into the Project References.
After you can use something like this to declare the dictionary:
Dim UseDict As Dictionary
Set UseDict = New Dictionary
To know if the Key you're searching is not in the Dictionary and then add the new user:
If Not UseDict.Exists(Key) Then
UseDict.Item(Key) = 1
End If
The Value is not important here, but if you wanted to count how many times a key appears somewhere, you could increment the value when UseDict.Exists(Key) = True.
That's what the Dictionaries, Hash-maps or Maps stand for: count and search efficiently.
Hope it helps!
I attach a code with some corrections. I think the problem is that you are trying to access to an array as if it was a variable. That means you have to loop through the item of a key.
I add comments to the code below:
Update
If UseList Is Nothing Then
Set UseList = New Dictionary
MsgBox "Created New"
End If
If UseList.Exists(rs("Alias")) Then
'i think is better to specify the data type and the dimension.
Dim temp(10) as string
'if you loop from 0 to 10 the array will have 11 elements
For i = 0 To 9
temp(i) = rs(i + 1)
Next i
'This will work also and looks nicer (in my opinion) than the method
'you pasted, but if that worked anyway don't change it ;)
UseList(rs("Alias")).Item = temp
End If
Now, if you want to retrieve the result you must:
For i = 0 To UBound(UseList.Item(rs("Alias")) - 1
Debug.Print UseList.Item(rs("Alias"))(i)
Next i
Give me feedback when you test the code, please :)

Grouping an array

PLEASE...Help me group the values in this array
I have a an array like this
Arr(0) = 5
Arr(1) = ATC^1
Arr(2) = BTC^2
Arr(3) = ATC^3
Arr(4) = CTC^4
Arr(5) = BTC^5
The end result I want is to change Arr(0) to be 3 which are the number of unique TC's in the group. ATC,BTC and CTC. And I want each of the items for 1,2 and 3 to have the grouped values from the Array.
Arr(0) = 3
Arr(1) = ATC:1,3
Arr(2) = BTC:2,5
Arr(3) = CTC:4
I am trying to do this in MUMPs, so I have no inbuilt sort/group functions.
Even pseudo code will help.
In MUMPS you don't need sort function because array subscripts are being automatically sorted.
So the easiest way is to create another array with sort dimension being first piece of data and value - second piece of data:
for i=1:1:Arr(0) set piece1=$piece(Arr(i),"^",1), piece2=$piece(Arr(i),"^",2), Temp(piece1)=$get(Temp(piece1))_piece2_","
after running that code you will get following array
Temp("ATC")="1,3,"
Temp("BTC")="2,5,"
Temp("CTC")="4,"
Then you traverse that array and build one you need:
set i="",Brr=0 for set i=$o(Temp(i)) quit:i="" set Brr=Brr+1,Brr(Brr)=i_":"_Temp(i)
You will get an array you need:
Brr(1)="ATC:1,3,"
Brr(2)="BTC:2,5,"
Brr(3)="CTC:4,"
Alternate:
Two dimension array:
Temp("ATC",1)=""
Temp("ATC",3)=""
Temp("BTC",2)=""
Temp("BTC",5)=""
Temp("CTC",4)=""
The $o loop can look through the first level for the items in sorted order, then a nested $o to run through the second. Or, just the first if you only want the sorted list. This would save the string logic if you are going to selectively remove elements from the list and just let you set and kill notes in the array.
Sorting logic is uncommon with MUMPS, data is normally loaded/stored into arrays like which keeps them in sorted order.

Resources