Why is my array being cleared? - arrays

I'm designing a slide checker to look for mismatched fonts and colours, and need to keep track of each colour for each shape in an array. My problem is that for some reason the array get's cleared. I've put in flags to check that the array is being properly assigned. As it moves through the loop, it correctly adds 1 to the array, updates the colour for that index, then moves forward. For some reason when it gets to the msgbox check, the array still has the correct number of indexes, but the array is empty for every shape except for the last shape in the loop. For example one shape has 5 lines, another shape has 2. I'll get a msgbox 7 times, but the first 5 are empty, and the next 2 have the actual colour.
Private Sub CommandButton1_Click()
Dim x As Integer
Dim i As Integer
Dim a As Integer
Dim b As Integer
Dim shpCount As Integer
Dim lFindColor As Long
Dim oSl As Slide
Dim oSh As Shape
Dim colorsUsed As String
Dim fontsUsed As String
Dim lRow As Long
Dim lCol As Long
Dim shpFont As String
Dim shpSize As String
Dim shpColour As String
Dim shpBlanks As Integer: shpBlanks = 0
Dim oshpColour()
Set oSl = ActiveWindow.View.Slide
For Each oSh In oSl.Shapes
'----Shape Check----------------------------------------------------------
With oSh
If .HasTextFrame Then
If .TextFrame.HasText Then
shpCount = shpCount + .TextFrame.TextRange.Runs.Count
ReDim oshpColour(1 To shpCount)
For x = 1 To .TextFrame.TextRange.Runs.Count
a = a + 1
oshpColour(a) = .TextFrame.TextRange.Runs(x).Font.Color.RGB
shpFont = shpFont & .TextFrame.TextRange.Runs(x).Font.Name & ", "
shpSize = shpSize & .TextFrame.TextRange.Runs(x).Font.Size & ", "
shpColour = shpColour & .TextFrame.TextRange.Runs(x).Font.Color.RGB & ", "
Next
End If
End If
Next
MsgBox "Shape Fonts: " & shpFont & vbCrLf & "Shape Font Sizes: " & shpSize & vbCrLf & "Shape Font Colours: " & shpColour
For b = LBound(oshpColour) To UBound(oshpColour)
MsgBox oshpColour(b)
Next
End Sub

The right way to redim an array keeping it content is as follows:
ReDim Preserve oshpColour(1 To shpCount)

Related

How to write items from a ListBox into an Array VBA [duplicate]

I classify myself as a beginner in programing. I have a userform that first looks up a number presented by the user. Example 12345, 12346,12347. The number entered into the textbox is searched for and then added to the listbox as a valid number. After the user enters all the numbers needed, they should be able to click change and update the records accordingly.
Private Sub Change_Click()
Dim i As Long
For i = LBound(RunArray) To UBound(RunArray)
' Code to update each record, still working on it.
Next
End Sub
Private Sub RunNumber_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Dim RunArray() As String
Dim RunCount As Integer
RunCount = 0
If KeyCode = 13 Then
With Sheets("Sheet1").Range("A:A")
Set RunFind = .Find(What:=RunNumber, _
After:=.Cells(.Cells.count), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not RunFind Is Nothing Then
ReDim Preserve RunArray(RunCount)
RunArray(RunCount) = RunNumber.Value
RunNumberList.AddItem RunNumber.Value
RunNumber.Value = ""
RunCount = RunCount + 1
Else
MsgBox "The Run Number you entered was not found, Please the number and try again."
RunNumber.Value = ""
End If
End With
End If
End Sub
Private Sub CreateArrayFromListbox()
Dim nIndex As Integer
Dim vArray() As Variant
' dimension the array first instead of using 'preserve' in the loop
ReDim vArray(ListBox1.ListCount - 1)
For nIndex = 0 To ListBox1.ListCount - 1
vArray(nIndex) = ListBox1.List(nIndex)
Next
End Sub
i have an example how to do it with a combobox, (it's the same with a listbox, just change the name accordingly.
Option Explicit
Private Sub UserForm_Initialize()
Dim i&
Dim Arr()
With Me.ComboBox1
For i = 1 To 1000
.AddItem "Item " & i
Next i
Arr = .List
.Clear
End With
For i = 0 To 999
Debug.Print Arr(i, 0)
Next i
Erase Arr
End Sub
this is just a sample code, in real coding, you won't clear the combobox this early, or erase the array.
The results are shown in the immediate window (alt-F11 , and Ctrl-g).
Note : the array is 2 dimendionned, and 0 based (Option base 1, after Option Explicitcan make the whole module 1-based (arrays start at 1) ).

How do I extract the last name from each cell in a name column and assign it to name array?

I think i've got a good start, but I'm having a tough time taking this to the finish line. Could someone help me out?
I have a name column(G) in my spreadsheet. I want to pull the only the last name out of each cell and assign it to an array called name_array.
I know that my If function is working because if I set each name_cell to the LastName variable it substitutes only the lastname in each cell of the column, but I cannot figure out how to assign that to the array.
Here is my code thus far. Can someone please help me out and point out what I'm missing?
Sub create_namear()
Dim name_array() As Variant
Dim name_range As Range
Dim name_cell As Range
Dim n As Long
Set name_range = ActiveSheet.Range("G2:G" & Range("G" & Rows.Count).End(xlUp).Row)
ReDim name_array(name_range.Cells.Count)
For Each name_cell In name_range.Cells
Dim Lastname As String
If InStr(name_cell, " ") > 0 Then
Lastname = Split(name_cell, " ")(1)
End If
name_array(n) = lastname.value
n = n + 1
Next name_cell
Debug.Print name_array(1)
End Sub
Name Column
Here is another way to achieve what you want without looping. I have commented the code so you should not have a problem understanding it.
BASIC LOGIC
To get the part after SPACE, you can use the formula =IFERROR(MID(G2,SEARCH(" ",G2,1),LEN(G2)-SEARCH(" ",G2,1)+1),"")
Now applying the formula in the entire range and getting the value using INDEX(FORMULA). You can find the explanation of this method in Convert an entire range to uppercase without looping through all the cells
CODE
Option Explicit
Sub Sample()
Dim ws As Worksheet
Dim rng As Range
Dim lRow As Long, i As Long
Dim FinalAr As Variant
'~~> Set this to the relevant sheet
Set ws = Sheet1
With ws
'~~> Find last row in col G
lRow = .Range("G" & .Rows.Count).End(xlUp).Row
'~~> Set your range
Set rng = .Range("G2:G" & lRow)
'~~> Get all the last names from the range and store them
'~~> in an array in 1 go!
FinalAr = Evaluate("index(IFERROR(MID(" & _
rng.Address & _
",SEARCH("" ""," & _
rng.Address & _
",1),LEN(" & _
rng.Address & _
")-SEARCH("" ""," & _
rng.Address & _
",1)+1),""""),)")
End With
'~~> Check the output
For i = LBound(FinalAr) To UBound(FinalAr)
Debug.Print ">"; FinalAr(i, 1)
Next i
End Sub
IN ACTION
ALTERNATIVE METHODS
Use Text To columns and then store the output in an array
Use Flash Fill to get the last names and then store the output in an array. One drawback of this method is that the names which do not have last name, it will show first name instead of a blank.
Sub create_namear()
Dim name_array() As Variant
Dim name_range As Range
Dim name_cell As Range
Dim n As Long
Set name_range = ActiveSheet.Range("G2:G" & Range("G" & Rows.Count).End(xlUp).Row)
ReDim name_array(0 to name_range.Cells.Count-1) '### 0-based array...
For Each name_cell In name_range.Cells
If InStr(name_cell, " ") > 0 Then
name_array(n) = Split(name_cell, " ")(1) 'simplify...
End If
n = n + 1
Next name_cell
Debug.Print name_array(1)
End Sub
Solution using Filter() (values with missing lastnames are excluded):
Sub ExtractLastNames()
Dim arr, name_array, i
arr = WorksheetFunction.Transpose(Range("G2:G" & Cells(Rows.Count, "G").End(xlUp).Row)) 'first, get the horizontal one-dimentional array from cells
name_array = Filter(arr, " ", True) 'second, filter out one-word and empty elements
For i = LBound(name_array) To UBound(name_array)
name_array(i) = Split(name_array(i))(1) 'third, replace name_array values with extracted lastnames
Next
Range("H2").Resize(UBound(name_array) + 1) = WorksheetFunction.Transpose(name_array) ' output
End Sub
Last Names to Array
The following will consider the substring after the last occurring space as the last name.
Option Explicit
Sub create_namear()
Dim ws As Worksheet: Set ws = ActiveSheet
Dim nRange As Range
Set nRange = ws.Range("G2:G" & ws.Range("G" & ws.Rows.Count).End(xlUp).Row)
Dim rCount As Long: rCount = nRange.Rows.Count
Dim nArray() As String: ReDim nArray(0 To rCount - 1)
Dim nCell As Range
Dim n As Long
Dim nmLen As Long
Dim LastSpacePosition As Long
Dim nmString As String
Dim LastName As String
For Each nCell In nRange.Cells
nmString = CStr(nCell.Value)
If InStr(1, nmString, " ") > 0 Then
LastSpacePosition = InStrRev(nCell.Value, " ")
nmLen = Len(nmString)
If LastSpacePosition < nmLen Then
LastName = Right(nmString, nmLen - LastSpacePosition)
nArray(n) = LastName
n = n + 1
End If
End If
Next nCell
If n = 0 Then Exit Sub
If n < rCount Then
ReDim Preserve nArray(0 To n - 1)
End If
Debug.Print "[" & LBound(nArray) & "," & UBound(nArray) & "]" _
& vbLf & Join(nArray, vbLf)
End Sub
Extension on Siddharth' s formula evaluation
These additions to Siddharth's valid code can be helpful, if there are less than 2 data rows in order to avoid
an unwanted evaluation of the title row 1:1 (in case of no data at all, see section 1.b) - This can be prevented by correcting a resulting row number lRow of only 1 to the actual data row start of 2.
Error 9 Subscript out of range (in case of a single element; see section 3.b) - Note that this requires to transform a 1-dim result to a 2-dim results array by means of a adequately dimensioned tmp array.
Furthermore I simplified the formula building to avoid repeated rng.Address insertions just to show another way of doing it (see section 2.).
Sub GetLastName()
'0. Set this to the relevant sheet
Dim ws As Worksheet: Set ws = Sheet1
With ws
'1. Define data range
'1. a) Find last row in col G
Dim lRow As Long
lRow = .Range("G" & .Rows.count).End(xlUp).Row
'1. b) Provide for empty data set ' << Added to avoid title row evaluation
If lRow = 1 Then lRow = 2
'1. c) Set your range
Dim rng As Range: Set rng = .Range("G2:G" & lRow)
'2. Define formula string parts ' << Modified for better readibility
Dim FormulaParts()
FormulaParts = Array("INDEX(IFERROR(MID(", _
",SEARCH("" "",", _
",1),LEN(", _
")-SEARCH("" "",", _
",1)+1),""""),)")
'3. Assign last names to 2-dim array results
'3. a) Get all the last names from the range and store them
Dim results
results = Evaluate(Join(FormulaParts, rng.Address))
End With
'3.b) Provide for single results '<< Added to avoid Error 9 Subscript o/Rng
If UBound(results) = 1 Then '<< Force single element into 2-dim array
Dim tmp(1 To 1, 1 To 1)
tmp(1, 1) = results(1)
results = tmp
End If
'h) Display in VB Editor's immediate window
Dim i As Long
For i = LBound(results) To UBound(results)
Debug.Print ">"; results(i, 1)
Next i
'i) Write last names to target '<< Added to demonstrate writing back
ws.Range("H2").Resize(UBound(results), 1) = results
End Sub

For Loop range not working: Wrong number of arguments or invalid property assignment

I have the following code which scans a list of raw data and for each line and if date and var (a variant I defined) are correct the row is copied and placed into the correct destination. This line to copy row is commented out. The macro worked but instead of copying the whole row I've now attempted (in the 2 lines above the commented out .copy row) to select only specific cells in the row (cells in iRow and columns M,N,O,Q,R,U,V,AB). I get the error: Wrong number of arguments or invalid property assignment. I know this is related to the 2 new lines of code I input because previously the code worked fine. Any help is appreciated, thanks!
Sub currentMonthDetail()
Dim csCount As Range
Dim b As Variant
Dim shrow As Long
Dim iRow As Long, iRowL As Long, var As Variant, iDate As Variant
Dim bln As Boolean
Dim s As String
Dim eRow As Integer
Dim i As Integer
'Import monthly data from GL008 tab to detail-----------------------------------------------------------------
Set csCount = Worksheets("Input").Range("csCount")
Sheets("GL008").Activate
iRowL = Cells(rows.count, 1).End(xlUp).Row
For iRow = 2 To iRowL
Sheets("GL008").Activate
If Not IsEmpty(Cells(iRow, 35)) Then
bln = False
var = Application.Match(Cells(iRow, 35).Value, Worksheets("Input").Columns(3), 0)
iDate = Sheets("GL008").Cells(iRow, 34)
If Not CVErr(var) = CVErr(xlErrNA) And iDate = Worksheets("Input").Range("E3") Then
Sheets("GL008").Activate
Range("M" & iRow, "N" & iRow, "O" & iRow, "Q" & iRow, "R" & iRow, "U" & iRow, "V" & iRow, "AB" & iRow).copy
'Sheets("GL008").rows(iRow).copy
s = Sheets("GL008").Cells(iRow, 35)
Sheets(s).Activate
eRow = Sheets(s).Cells(rows.count, 1).End(xlUp).Offset(1, 0).Row
ActiveSheet.Paste Destination:=Sheets(s).rows(eRow)
End If
End If
Next iRow
You are passing lots of cells to Range. When you try to do that, it's looking for a top-left start cell, a lower-right end cell, and will make a rectangle selection from one to the other.
Because you're trying to give it 8 separate parameters, it can't handle it. You need to give it 1 parameter, which contains the cell list; make them all into one string, and then give that string as one parameter to range.
i.e. put the commas into the text.
Range("M" & iRow & ",N" & iRow & ",O" & iRow & ",Q" & iRow & ",R" & iRow & ",U" & iRow & ",V" & iRow & ",AB" & iRow).copy

VBA Loop for copying data from cell to array

I'm new to VBA in excel, I write code for copying cells from sheet to an array. When I run I got run time error. I don't know whats wrong.
Sub DistSystem()
Dim count As Integer
Dim i As Integer
Dim array_rank() As Variant
Dim array_city() As Variant
Dim array_assign() As Variant
count = Sheets("111").Range("Y2").Value
For i = 0 To count
array_city(i) = Range("A" & i).Value
array_rank(i) = Range("E" & i).Value
array_assign(i) = Range("F" & i).Value
Next
For i = 1 To 10
MsgBox array_rank(i, 1)
Next
End Sub
I suspect you are going to be battle errors in multiple places.
This section of code has 2 significant problems
array_city(i) = Range("A" & i).Value
array_rank(i) = Range("E" & i).Value
array_assign(i) = Range("F" & i).Value
First you are trying to assign values to array that do not have any dimensions. You decleared the arrays but you left them dimensionless. You need to define the dimensions before you try to assign values to the array
Something like
Redim array_city(1 to count)
Next you are trying to get a value from Range("A" & i) when the value of i is zero. Cell "A0" does not exists and will also throw an error.
So to rewrite your code as written, you would need to make a few changes:
Sub DistSystem()
Dim count As Integer
Dim i As Integer
Dim array_rank() As Variant
Dim array_city() As Variant
Dim array_assign() As Variant
count = Sheets("111").Range("Y2").Value
Redim array_rank(1 to count)
Redim array_city(1 to count)
Redim array_assign(1 to count)
For i = LBound(array_rank) To UBound(array_rank)
array_city(i) = Range("A" & i).Value
array_rank(i) = Range("E" & i).Value
array_assign(i) = Range("F" & i).Value
Next
For i = 1 To 10
MsgBox array_rank(i)
Next
End Sub
However, you are over complicating how you are reading the values into the array. You can simply read the entire range directly into the array
Sub DistSystem()
Dim count As Integer
Dim i As Integer
Dim array_rank As Variant 'Notice the arrays are not longer declared with ()
Dim array_city As Variant ' -> this is necessary
Dim array_assign As Variant
count = Sheets("111").Range("Y2").Value
array_city = Range("A1:A" & count).Value
array_rank = Range("E1:E" & count).Value
array_assign = Range("F1:F" & count).Value
For i = 1 To 10
MsgBox array_rank(i, 1)
Next
End Sub
The resulting array with be 2 dimensions, with the Row value as the first dimension and the column as the 2nd dimension. since all of the ranges are a single column, you would access any value by calling array_rank(Row,1) or array_city(Row,1) or array_assign(Row,1).

Creating an array variable with a variable number of elements

I want to define an array variable to have a variable number of elements depending on the m number of results returned from a search. I get an error "Constant Expression Required" on:
Dim cmodels(0 To m) As String
Here is my complete code
Dim foundRange As Range
Dim rangeToSearch As Range
Set rangeToSearch = Selection
Set foundRange = rangeToSearch.Find(What:="Lights", After:=ActiveCell,
LookIn:=xlValues, LookAt:= _
xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False _
, SearchFormat:=False) 'First Occurrence
m = WorksheetFunction.CountIf(Selection, "Lights")
Dim secondAddress As String
If (Not foundRange Is Nothing) Then
Dim count As Integer: count = 0
Dim targetOccurrence As Integer: targetOccurrence = 2
Dim found As Boolean
z = 1
Dim cmodels(0 To m) As String
Do Until z = m
z = z + 1
foundRange.Activate
Set foundRange = rangeToSearch.FindNext(foundRange)
If Not foundRange.Next Is Nothing Then
z(m) = ActiveCell(Offset(0, 2))
End If
Loop
End If
End Sub
See the following code comments:
Sub redimVsRedimPreserve()
'I generally declare arrays I know I will resize
'without a fixed size initially..
Dim cmodels() As String
Dim m As Integer
m = 3
'this will wipe out all data in the array
ReDim cmodels(0 To m) As String
'you can also use this if you want to save all information in the variable
cmodels(2) = "test"
ReDim Preserve cmodels(0 To m) As String
'this will still keep "test"
Debug.Print "With redim preserve, the value is: " & cmodels(2)
'using just 'redim'
ReDim cmodels(0 To m) As String
Debug.Print "with just redim, the value is: " & cmodels(2)
End Sub
Also note that using Redim Preserve frequently (such as a loop) can be an operation which takes some time.
Dim cmodels() As String
'...
ReDim cmodels(0 to m)

Resources