I'm trying to create an array with only unique values (Signal Names). For example my spreadsheet looks like this
Voltage
Voltage
Voltage
Current
Current
Current
etc....
I've got 32 signals however, I want this to work even if I don't know I have 32 signals explicitly i.e. 17 signals.
Signals("Voltage", "Current", "Etc....")
IN THE CODE BELOW
I realize I'm trying to ReDim an array within a loop and that's the problem. I'm just not able to think of another way of doing this. I would prefer to keep it as an array problem and not a dictionary or collection problem for now.
Public Sub Signals()
Dim myArray() As Variant
Dim Signals() As Variant
Dim element As Variant
Dim intA As Integer
WsName = ActiveSheet.Name
intRows = Sheets(WsName).Range("B2", Sheets(WsName).Range("B" & Sheets(WsName).Rows.Count).End(xlUp)).Rows.Count
intRows = intRows + 1
ReDim Signals(1)
Signals(1) = Sheets(WsName).Cells(4, 2).Value
For intA = 4 To intRows
For Each element In Signals()
If element <> Sheets(WsName).Cells(intA, 2) Then
ReDim Signals(UBound(Signals) + 1) 'This throws the error
Signals(UBound(Signals)) = Sheets(WsName).Cells(intA, 2).Value
End If
Next element
Next
End Sub
How the code doesn't work - RunTime Error '10' Array is temporarily fixed or locked.
I posted a solution to this issue using arrays in a similar question a couple days ago - using column B for your case, this would do the trick.
Aside from this solution, you have several problems in your current code - you're testing against each individual element in your current array without checking them all first, you're not using ReDim Preserve, and you need (0 to 0), not just a single (0) or (1). You're also naming your subroutine "Signals" while attempting to declare a variable "Signals" in the subroutine as well... That'll cause all kinds of issues.
Sub Test()
Dim list() As Variant
Dim inlist As Boolean
Dim n As Long, i As Long, j As Long, endrow As Long, colnum As Long
ReDim list(0 To 0)
inlist = False
j = 0
colnum = 2 'Column B in this case
endrow = Cells(Rows.Count, colnum).End(xlUp).Row
For n = 1 To endrow
For i = 0 To UBound(list)
If list(i) = Cells(n, colnum).Value Then
inlist = True
Exit For
End If
Next i
If inlist = False Then
ReDim Preserve list(0 To j)
list(j) = Cells(n, colnum).Value
j = j + 1
End If
inlist = False
Next n
For i = 0 To UBound(list)
Debug.Print list(i)
Next i
End Sub
Even simpler solution thanks to #user10829321's suggestions:
Sub Test()
Dim list() As Variant
Dim n As Long, i As Long, j As Long, endrow As Long, colnum As Long
ReDim list(0 To 0)
j = 0
colnum = 2 'Column B in this case
endrow = Cells(Rows.Count, colnum).End(xlUp).Row
For n = 1 To endrow
If IsError(Application.Match(Cells(n, colnum).Value, list, 0)) Then
ReDim Preserve list(0 To j)
list(j) = Cells(n, colnum).Value
j = j + 1
End If
Next n
For i = 0 To UBound(list)
Debug.Print list(i)
Next i
End Sub
An optional, if perhaps unwanted, solution using a scripting dictionary to give an array.
Public Function Signals(ByRef this_worksheet_range As excel.Range) As Variant()
Dim myArray() As Variant
Dim element As Variant
Dim interim_dic As Scripting.Dictionary
myArray = this_worksheet_range.values2
Set interim_dic = New Scripting.Dictionary
For Each element In myArray
If Not interim_dic.Exists(element) Then
interim_dic.Add Key:=element, Item:=element
End If
Next
Signals = interim_dic.Items
End Function
I had an dynamic array where is value is from the worksheet.
If condition is meet, I would like to delete the element that meet the condition. The code was from this post but it is returning
Type Mismatch
on ReDim Preserve arr(Len(arr) - 1)
Sub arrtest()
Dim arr As Variant
Dim i As Integer
ReDim arr(1 To 1)
Dim cnt As Long
cnt = 0
For i = 1 To Cells(Rows.Count, "L").End(xlUp).Row
If Cells(i, "A").Value = "-2" Then
cnt = cnt + 1
ReDim Preserve arr(1 To cnt)
arr(cnt) = Cells(i, "A").Value
End If
Next i
For i = 1 To cnt
Debug.Print "This is arr: "; arr(i)
If arr(i) = "TEST" Then
Call DeleteElementAt(i, arr)
Debug.Print "This is new arr: "; arr(i)
Else
Debug.Print "Nothing is deleted"
End If
Next
End Sub
Public Sub DeleteElementAt(ByVal index As Integer, ByRef arr As Variant)
Dim i As Integer
' Move all element back one position
For i = index + 1 To UBound(arr)
arr(i - 1) = arr(i)
Next
' Shrink the array by one, removing the last one
ReDim Preserve arr(Len(arr) - 1)
End Sub
The Len (or Length) of an array is its Upper Boundary. To decrease the size of the array by 1,
ReDim Preserve arr(UBound(arr) - 1)
Conversely, the beginning of an array is the LBound or lower boundary. This is usually 0 (zero) or 1 (one) and in a two-dimensioned array you can specify the rank.
I want to redim an one-dimentional array by "cutting off" the first five entries as they have to be removed for a later logic.
I created a record set from a query
I filled an array recordSet() As Variant (size is 147).
Now: size of recordSet = size of daoRst3
I try to remove the first five elements of the array recordSet.
Code:
Set daoRst3 = gDB.OpenRecordset("SELECT * FROM TEST")
For i = 0 To daoRst3.Fields.Count - 1
ReDim Preserve recordSet(0 To i)
If daoRst3.Fields(i).Value = Empty Then
recordSet(i) = 0
Else: recordSet(i) = daoRst3.Fields(i).Value
End If
Next
'First five values in record set are not needed anymore.
ReDim Preserve recordSet(5 To i - 1)
The last row
ReDim Preserve recordSet(5 To i - 1)
throws "Subscript out of range". I already checked with debugging that i is 148 at this moment.
What might be the problem?
Many thanks in advance!
Alright this time i got it...
Private Sub this()
Dim rs As DAO.Recordset
Set rs = CurrentDb.OpenRecordset("SELECT * FROM tmpCardList")
Dim msg As String
Dim myArray() As String
Dim array2() As String
ReDim array2(0 To rs.Fields.Count - 1)
Dim i As Long
For i = 0 To rs.Fields.Count - 1
Debug.Print ; rs.Fields(i).Name
array2(UBound(array2, 1) - i) = rs.Fields(i).Name
Next i
ReDim Preserve array2(UBound(array2) - 5)
ReDim myArray(0 To UBound(array2, 1))
For i = 0 To UBound(array2, 1)
myArray(UBound(array2, 1) - i) = array2(i)
Next i
rs.Close
Set rs = Nothing
End Sub
Turns out you have to write you own custom thing to sort the array. A little bit of an extra hoop. Just realized the final output is reversed but you could easily "undo" that by replicating my initial reversing logic.
Final Edit - this time with less typing - WOOHOO
I create an array in vba by looping through cells in a sheet (originalWS). So let's say cells (2,5) to (2,12) have the following:
(2,5)Item
(3,5)Type
(4,5)Nominal Diameter
(5,5)Lead
.
.
.
(12,5)For Use with End Blocks
Thus, when I loop with the code below I get an array that looks like this:
[Item,Type,Nominal Diameter,Lead,...,For Use with End Blocks].
However, I would like to add two empty spaces between each value in my array. so that it looks like this:
[Item,"","",Type,"","",Nominal Diameter,"","",Lead,"","",...,For Use with End Blocks,"",""]
ReDim propertyArr(1, lastRow)
For i = 1 To lastRow
propertyArr(1, i) = originalWS.Cells(i + 1, 5).Value
Debug.Print propertyArr(1, i)
Next
I have tried to loop to by the final total size of the array so (lastRow*3) and step forward by 3. However, I'm having a hard time figuring out how I would reset my orginalWS.cells(i,5) values so that they are consecutive.
In other words, when I loop stepping by 3 my values would be:
propertyArr(1,1) = originalWS.Cells(2,5).value
propertyArr(1,4) = originalWS.cells(5,5).value
propertyArr(1,7) = originalWS.cells(8,5).value
How can I loop so that I store values in my array every 2 places, while I get the values from a consecutive list in a sheet.
Can I do this without having to add extra empty row
a way to add two empty spaces between each value within my original loop without having to add extra empty rows?
Or, can I add the two empty spaces between each value after I created my array the first time?
This should do the trick,
Dim lRowNo As Long
lRowNo = lastRow * 3
ReDim propertyArr(1, lRowNo)
For i = 1 To lRowNo
If i Mod 3 = 1 Then
propertyArr(1, i) = originalWS.Cells(i + 1, 5).Value
Else
propertyArr(1, i) = ""
End If
Debug.Print propertyArr(1, i)
Next
Something like:
Sub ytrewq()
Dim propertyArr(), lastRow As Long
Dim originalWS As Worksheet
Set originalWS = ActiveSheet
lastRow = 5
ReDim propertyArr(1, 2 * lastRow)
For i = 1 To 2 * lastRow Step 2
propertyArr(1, i) = originalWS.Cells(i + 1, 5).Value
propertyArr(1, i + 1) = ""
Debug.Print propertyArr(1, i)
Next
End Sub
UNTESTED
You can also unroll the loop a bit to do this a bit more efficiently. Note that for each iteration, i isn't incremented by 1, but by 3.
Public Sub test()
Dim lastRow As Long
lastRow = 6
Dim lastIndex As Long
lastIndex = lastRow * 3
ReDim propertyArr(1 To lastIndex)
Dim i As Long
For i = 1 To lastIndex Step 3
propertyArr(i) = CInt(i / 3)
propertyArr(i + 1) = vbNullString
propertyArr(i + 2) = vbNullString
Next
End Sub
Or without loops
Dim ws As Worksheet
Set ws = Sheets(1)
propertyarr = Join(Application.Transpose(ws.Range("E1:E5")), ","""","""",")
to put back into array
propertyarr = Split(Join(Application.Transpose(ws.Range("E1:E5")), ",,,"), ",")
I figured out the answer. I wasn't updating the cells I needed correctly. See code below:
count = 3
lastIndex = lastRow * 3
ReDim propertyArr(1, lastIndex)
For i = 1 To lastIndex Step 3
propertyArr(1, i) = originalWS.Cells((count - 1), 5)
count = count + 1
Next
I have the below code that adds values to an array if it meets a criteria.
It keeps looping horizontally through the columns across a row and then repeats the same for the next row and so on.
I am trying to clear the values accumulated in the array and empty it at the end of the columns loop:
For a = 21 To 23
Count = 0
For b = 2 To 36
If Not Worksheets("Sheet1").Cells(a, b).Value = "A" And Not Worksheets("Sheet1").Cells(a, b).Value = "B" Then
Count = Count + 1
Else
If Not Count = 0 Then
Dim arr() As Long
arrLen = 1
ReDim Preserve arr(1 To arrLen)
arr(arrLen) = Count
arrLen = arrLen + 1
For i = LBound(arr) To UBound(arr)
msg = msg & arr(i) & vbNewLine
Next i
Count = 0
End If
End If
Next b
MsgBox Worksheets("Sheet1").Cells(a, 1).Value & vbNewLine & msg
Erase arr 'not working
Next a
As you can see from the above code, I get a msgbox displaying the values at the end of each loop, however as it continues, the array keeps getting bigger and bigger indicating that the Erase line is not working.
Kindly help!
You can either use a loop to set the array elements to nulls, or ReDim the array away:
Sub marine()
Dim arr()
ReDim arr(1 To 2)
arr(1) = "Alpha"
arr(2) = "Beta"
ReDim arr(1 To 1)
arr(1) = ""
End Sub
That way you can re-use the same array name later in the sub.