Erase arrays with a variable - arrays

I'm creating a macro with a data sheet that has 185 columns. I need to capture the data in each column for the total number of rows in the data sheet (maybe 800).
I want to capture all of the data so I created variables like this so the number corresponds to the the column number:
Public vVar1() as string
Public vVar2() as string
Public vVar3() as string
Public vVar4() as string.....etc.
I want to erase the array and I'm trying to do something like this:
vCnt = 1
vTmp = ""
Do Until vCnt = 186
DoEvents
vTmp = "vVar"
vTmp = vTmp & vCnt
Erase vTmp
vCnt = vCnt + 1
Loop
However, I'm getting an "Expected Array" error message on the "Erase vTmp" line. I was trying to do it this way instead of having ERASE vTMP1, ERASE vTmp2.....183 more times.
Is there a way to do this? Thanks......Any suggestions would be greatly appreciated. Thanks again.

Erase vTmp
vTmp is a Variant/String here, not an array. Just because the string happens to match the name of a programmatic identifier doesn't make it a magical string that arbitrarily becomes an actual identifier depending on context like it would in PHP - and that's a very, very good thing.
The real problem is having 185 arrays to clear in the first place. Whenever you feel the need to number something - anything - there's a 99% chance you're in the wrong spot and need to think of a data structure instead. Like Tim said, an array with 185 items that are themselves arrays makes much more sense than having 185 variables that go by the names of vVar1 through vVar185.
And then you can Erase them, because now you're dealing with arrays, not strings:
For i = 0 To 184
Erase allArrays(i)
Next

Related

Excel VBA: How to concatenate variant array elements (row numbers) into a range object?

I did research this question but could not find the specific answer I was looking for and am actually even more confused at present.
I created a macro that would run through rows on a sheet and run boolean checks on a number of cells in each row that looked for the presence or absence of specific values, or calculated the outcome of a specific inequality. On the basis of those checks, the macro may or may not pass the row number into a specific array. That part is working fine.
My issue is, now that I have the row numbers (stored in variant arrays) - I cannot figure out how to properly concatenate that data into a range and then take a bulk excel action on those items. What I'd like to do is create a range of those values and then delete all of those rows at once rather than looping through.
My macro is on my work computer, but here's something I wrote that should explain what I'm trying to do:
Sub Test()
Dim Str As String
Dim r As Range
Dim i, a As Integer
Dim Count As Integer
Dim RngArray()
Count = ThisWorkbook.Sheets("Sheet1").Cells(Rows.Count, "A:A").End(xlUp).Row
ReDim RngArray(Count)
a = 0
For i = 1 To Count
If Not i = Count Then
RngArray(a) = i
Str = Str & RngArray(a) & ":" & RngArray(a) & ", "
a = a + 1
ElseIf i = Count Then
RngArray(a) = i
Str = Str & RngArray(a) & ":" & RngArray(a)
a = a + 1
Else: End If
Next i
Set r = Range(Str)'Error Can Appear here depending on my concatenation technique
Range(Str).EntireRow.Delete 'error will always appear here
End Sub
I've combined a few steps here and left out any Boolean checks; in my actual macro the values in the arrays are already stored and I loop from LBound to UBound and concatenate those values into a string of the form ("1:1, 2:2, 3:3, ...., n:n")
The reason why I did this is that the rows are all over the sheet and I wanted to get to a point where I could pass the argument
Range("1:1, 2:2, 3:3, ..., n:n").EntireRow.Delete
I think it's clear that I'm just not understanding how to pass the correct information to the range object. When I try to run this I get a "Method Range of Object Global" error message.
My short term fix is to just loop through and clear the rows and then remove all of the blank rows (the macro keeps track of absolute positions of the rows, not the rows after an iterative delete) - but I'd like to figure out HOW to do this my way and why it's not working.
I'm open to other solutions as well, but I'd like to understand what I'm doing wrong here. I should also mention that I used the Join() to try to find a workaround and still received the same type of error.
Thank you.
After some experimentation with my dataset for the macro above, I discovered that it worked on small sets of data in A:A but not larger sets.
I ran Debug.Print Len(Str) while tweaking the set size and macro and found that it appears Range() can only accept a maximum of 240 characters. I still don't understand why this is or the reason for the specific error message I received, but the macro will work if Len(Str) < 240.
I'll have to loop backwards through my array to delete these rows if I want to use my present method...or I may just try something else.
Thanks to Andrew for his attention to this!

Retrieving values of Mode Array in Excel

We have some spreadsheets with thousands of numbers where we would like to return the mode arrays. MODE.MULT can only handle 254 numbers.
Trying to overcome this, we split the mode arrays to check 252 cells of a single column. We were then going to check the Mode from among these numbers (understanding that this adds a degree of error, but considering the set size, we believe it to be small).
This led us to assigning a jagged array to the mode function, but we're having problems retrieving the values therein:
Dim ModeArray() As Variant 'Also tried ModeArray as not an array of variants but that left the same errors
Dim RowSet As Integer
RowSet = 2
Dim rr As Range
For n = 2 To 252
Set rr = Sheet5.Range(Sheet5.Cells(7, n), Sheet5.Cells(260, n))
If Application.WorksheetFunction.CountBlank(rr) < 253 Then
'Needed because a 1004 error will pop if there are no numbers in a particular column
ModeArray = Application.WorksheetFunction.Mode_Mult(rr)
For i = 1 To UBound(ModeArray)
Sheet5.Cells(RowSet, n).Value = ModeArray(i)
'We get a few different errors. E.g. sub script out of range errors or if (1)(1) is tested "Object doesn't support this property or method (Error 438)" even though the TypeName(ModeArray(i)) is Double
RowSet = 1 + RowSet
Next
RowSet = 2
End If
Next
We are only expecting 2-3 modes per column, but gave space for 5. That's not our problem, however. Trying to retrieve the information out of ModeArray doesn't work, and it's type is Variant().
How can we get the actual values of the mode out, so we can report them in another table? I'm aware I could put in array functions directly in the worksheet, but I'd like to avoid dealing with "N/A" values down stream, and I don't have a way to determine the length of the mode array in a function.
Alternatively, is there a way to skip this all together and retrieve the modes of a very large data set?
Edit:
I should note that the above script will work if there is only one Mode, it's a problem if there are more than one modes.
MODE.MULT can handle more than 254 numbers in each parameter - its limitation is that it cannot handle more than 254 different parameters.
Sub modes()
Dim modearray As Variant
Dim j As Long
modearray = Application.WorksheetFunction.Mode_Mult(Range("Sheet1!A:B"))
If UBound(modearray) = 1 Then
Debug.Print modearray(1)
Else
For j = LBound(modearray) To UBound(modearray)
Debug.Print modearray(j, 1)
Next j
End If
End Sub
This works (a little slowly) for several thousand numbers in cols A & B

Array of 600+ Strings in excel VBA

I am doing a loop for each string in an array such that
filename = Array(file1,file2.....file600)
However VBA gets a compile error that is due to the array taking up 8 lines. As far as I am aware it only allows 1 line
(error says expected list or separator)
I am new to VBA sorry
You can escape new lines in VBA with _.
so your solution might look like
filename = Array("file1", _
"file2", _
"file3")
See How to break long string to multiple lines and If Statement With Multiple Lines
If you have 100's of names, however, you might be better off storing them in a worksheet and reading them in, rather than hard-coding them.
Should you strings in the array be actually "buildable" following a pattern (like per your examples: "file1", "file2", ...,"file600") then you could have a Function define them for you, like follows:
Function GetFileNames(nFiles As Long) As String()
Dim iFile As Long
ReDim filenames(1 To nFiles) As String
For iFile = 1 To nFiles
filenames(iFile) = "file" & iFile
Next
GetFileNames = filenames
End Function
which you'd call in your "main" code as follows
Sub main()
Dim filenames() As String
filenames = GetFileNames(600) '<--| this way'filenames' array gets filled with 600 hundred values like "file1", "file2" and so on
End Sub
The amount of code that can be loaded into a form, class, or standard module is limited to 65,534 lines. A single line of code can consist of up to 1023 bytes. Up to 256 blank spaces can precede the actual text on a single line, and no more than twenty-four line-continuation characters ( _) can be included in a single logical line.
From VB6's Help.
when programming, you don't build an array this big mannually, never.
either you store each multiline-string inside a Cell, and at the end you buid the array like this :
option Explicit
Sub ArrayBuild ()
Dim Filenames() 'as variant , and yes i presume when using multi files, the variable name should have an "s"
With Thisworkbook.sheets("temp") 'or other name of sheet
Max = .cells(.rows.count,1).end(xlup).row '=max number of rows in column 1
Filenames = .range( .cells(1,1) , .cells(Max,1)).value2 ' this example uses a one column range from a1 to a[max] , but you could also use a multi column by changing the second .cells to `.cells(Max, ColMax)`
end with
'do stuff
erase Filenames 'free memory
End Sub
An other way is to build an array like you build a house by adding one brick at a time, like this :
Dim Filenames() as string 'this time you can declare as string, but not in the previous example
Dim i& 'counter
For i=1 to Max 'same max as in previous example, adapt code plz...
redim Preserve Filenames (1 to ubound(filenames)+1) 'this is an example for unknown size array wich grows, but in your case you know the size (here Max, so you could declare it `Dim Filenames (1 to Max)` from the start, just wanted to show every option here.
Filenames(i) = Cells (i,1).value2 'for example, but can be anything else. Also i'm beeing lazy and did not reference the cell to its sheet, wich i'd never do in actual coding...
next i
EDIT i did re-read your Question, and it is even easier (basically because you ommited the bracets in your post and corrected it as comment...), use
user3598756 's code plz. I thought File1 is a variable, when it should be written as "File1" .
EDIT 2 why bother build and array where Filename(x)="Filex" anyway? you know the result beforehand

Splitting text into 2d array

I am trying to split a block of text into a 2d array. I know how to split a line into an array of words, and I know how to split multiple lines into an array of lines, but I would like to do both simultaneously.
For example, I want this :
Tim is nice
Jim is mean
would become
((Tim,is,nice),(Jim,is,mean))
So Far, I have been able to use
Str1.Split(new String() {Environment.NewLine}, StringSplitOptions.None)
To make the example string into:
(Tim is nice,Jim is mean)
And I've used Str1.Split to convert "Tim is nice" into
(Tim,is,nice)
Also, if any of my code is bad syntax or anything like that let me know, I'm a Python programmer primarily.
This isnt a 2D array:
((Tim,is,nice),(Jim,is,mean))
That is a jagged array or an array of arrays. Since each line/sentence may not have the same number of words, it is a better choice. For your example, you will have an array of 2 to hold each "line", then each of those will hold an array of however many words there are.
Dim original = "Tim is nice" & Environment.NewLine & "Jim is very mean"
Dim lines = original.Split(New String() {Environment.NewLine.ToString},
StringSplitOptions.RemoveEmptyEntries)
Dim results(lines.Count - 1)() As String
For n As Int32 = 0 To lines.Count - 1
' store array of words to results(n)
results(n) = lines(n).Split(" "c)
Next
' glue a line back together and show it
Console.WriteLine(String.Join(" ", results(1)))
results(0) will hold the Tim words, results(1) will hold the Jim words. Results (of the writeline):
Jim is very mean

Filling an array, A$(X,X) in Commodore BASIC?

I am trying to fill A$(X,X) with "."s in Commodore BASIC.
This is what I have so far....but I'm not really sure what to do concerning ASCII values and such. Any commentary?
INPUT A$
FOR I = 0 TO X = DIM A$(X,X)
A$(".",x)
I'm still EXTREMELY confused on PET BASIC's API... Any suggestions would be GREATLY appreciated.
My answers are based around a youth in front of a Commodore 64 and may not be completely correct for the PET series. But seeing as you haven't had any other answers yet I'll give it a bash.
In the first line of your code you are requesting a string from the user and storing it in A$. The dollar sign denotes the variable is a string. In the second line, you are redefining A$ as a two dimensional array. The dimensions are both X which hasn't been defined. I don't recall DIM having a return value but I could be wrong.
The function to get an ASCII value from a char is ASC() and to convert back you use CHR$() such:
10 NUMA = ASC("A"): REM NUMA now contains 65
20 CHARA$ = CHR$(NUMA): REM CHARA$ now contains "A"
Something you should know is that these functions use "PET ASCII" which is slightly different to ASCII. It never caused me any problems but its something to remember.
FOR loops always have a NEXT to end the block such:
10 FOR A = 1 TO 10
20 PRINT A: REM Displays series of numbers.
30 NEXT
I'm not entirely clear what you're trying to achieve but hopefully I have at least given you enough pieces to work it out. From what I understand, you need something like:
10 INPUT "Please enter a number:", X
20 DIM A$(X, X)
30 FOR I = 0 TO X
40 FOR J = 0 TO X
50 A$(I, J) = "."
60 NEXT
70 NEXT

Resources