In vb.net I want to split a string into an array, I also want to be able to know how many indices are in the array.
In vb6
I would write it like this
dim v1, arrIN(), idcCount
v1 = "1,2,3,4,5"
arrin() = split(v1,",")
idcCount = ubound(arrin))
I can get this to actually put those values into an array using:
Dim arrIN() = Split(v1, ",")
But I cannot figure out how to get the count of indices
When I try to test this in the immediate window I get the message below
?UBound(arrIN())
Number of indices is less than the number of dimensions of the indexed array.
You may use arrVar.GetUpperBound(0) and arrVar.GetLowerBound(0) methods.
Have look at MSDN reference : Array.GetUpperBound(dimension)
Dim v1 As String = "1,2,3,4,5"
Dim arrIN() As String = Split(v1, ",")
'Gets the total number of elements in the array
Dim a As Integer = arrIN.Length
'Gets the index of the last element
Dim b As Integer = arrIN.GetUpperBound(0)
In this instance:
arrIN.Length = 5
arrIN.GetUpperBound(0)=4
The zero in GetUpperBound(0) is the dimension that you want the upper index for.
AVD gave you the right answer. I just added arrIN.Length just in case you needed it.
Related
I am using an array to process the values (and texts) I have in a sheet:
Dim arr As Variant
arr = Application.ActiveSheet.UsedRange
'do stuff
Application.ActiveSheet.UsedRange = arr
However, this has a side-effect: when dumping the array back into the cells, the cells formatting is changed by Excel's default behaviour. For example, numbers stored as text which start with "0" are converted to numbers, and the "0" gets deleted. Or texts like "1-11" are converted to dates ("November 1"); and probably some others which I have not spotted yet.
If I monitor the Locals window, the strings are being preserved as strings in the array until the very moment, so it is the unloading that messes things up.
Is there a way to avoid this behavior ?
Edit: I also tried:
Application.ActiveSheet.UsedRange.Value = arr
Application.ActiveSheet.UsedRange.Value2 = arr
Application.ActiveSheet.UsedRange.text = arr
Same result for each.
You can use the valuetype option to preserve formatting etc: 11 is xlRangeValueXMLSpreadsheet
Sub CopyWithFormat()
Dim var As Variant
var = Range("A8:A11").Value(11)
Range("C8:C11").Value(11) = var
End Sub
But that will make it difficult to modify the values in the array.
So its probably simplest to loop the array adding '
Sub CopyWithFormat2()
Dim var As Variant
Dim j As Long
var = Range("A8:A11").Value
For j = 1 To UBound(var)
If VarType(var(j, 1)) = vbString Then var(j, 1) = "'" & var(j, 1)
Next j
Range("C8:C11").Value = var
End Sub
Also try
YourRangeVariable.NumberFormat = "#"
YourRange.Value=Your Array
This will convert the range to text first. Works for me when using values like 01-11 and saves having to do a loop.
I have a spreadsheet of data that I want to put into a VBA array which then outputs unique values to a new sheet. I have got that to work so far. However, some of the cells in the original data have text separated by commas, and I want to add those to the array as well. I can't quite get that bit to work.
After the various 'dims', my code is
'Grabs the data to work with
Set rTable = Worksheets("Data Entry").Range("N1:N100", "P1:P100")
'Puts it into an array
MyArray = rTable.Value
'Sets where the data will end up
Set rCell = Worksheets("TestSheet").Range("A1:A100")
'Each unique entry gets added to the new array
On Error Resume Next
For Each a In MyArray
UnqArray.Add a, a
Next
'Add unique data to new location
For i = 1 To UnqArray.Count
rCell(i, 1) = UnqArray(i)
Next
I have tried doing a new variant to store the split data
SpArray = split(MyArray,", ")
and then have that here
MyArray = rTable.Value
SpArray = split(MyArray,", ")
and then refer to SpArray for the rest of the code
I've also tried to have as part of
For Each a in SpArray
but it doesn't work for me.
Do I need to do a separate loop on each cell of the array before I filter out the unique ones?
Yes, you need another loop. But if you set a reference to Microsoft Scripting Runtime and use a Dictionary object, you can eliminate the loop that writes to the range because Dictionary.Keys returns an array.
In this example, it attempts to split every entry on a comma and treats each of those as a unique. If there is no comma, Split returns the one value so it works in both cases. There's probably a small cost to splitting things that don't need to be split, but you won't notice until your range is much larger. And it makes the code cleaner, I think.
Sub WriteUniques()
Dim dcUnique As Scripting.Dictionary
Dim vaData As Variant
Dim vaSplit As Variant
Dim i As Long, j As Long
vaData = Sheet1.Range("$I$12:$I$62").Value
Set dcUnique = New Scripting.Dictionary
For i = LBound(vaData, 1) To UBound(vaData, 1)
vaSplit = Split(vaData(i, 1), ",")
For j = LBound(vaSplit) To UBound(vaSplit)
If Not dcUnique.Exists(vaSplit(j)) Then
dcUnique.Add vaSplit(j), vaSplit(j)
End If
Next j
Next i
Sheet1.Range("J12").Resize(dcUnique.Count, 1).Value = Application.Transpose(dcUnique.Keys)
End Sub
The code tweak that worked for me was to put the Split at the end.
'Add unique data to new location
For i = 1 To UnqArray.Count
rCell(i, 1) = Split(UnqArray(i), ",")
Next
This then built up an array using data from different ranges and splitting up comma separated ones before outputting only the unique ones.
I have a string array A where I store some values for instance A(1) = "a,b,c" A(2)="1,2" etc. From that array I am creating subarrays using A(1).split(",") and I have
dim subArr1() as string = {"a","b","c"}
dim subArr2() as string = {"1","2"}
etc
Now, I want to create a new two-dimensional array
dim all()() as string = {subArr1, subArr2, ...}
The initial array is created dynamically and could be have 2, 5, or whatever number of items. So I could have any number of subArrays (subArrX)
Any idea how to deal with that? I am writing in vb.net 2013
Thank you
You could use this little LINQ query:
Dim A As String() = {"a,b,c", "1,2"}
Dim parts As IEnumerable(Of String()) = From str In A Select str.Split(","c)
Dim all()() As String = parts.ToArray()
Now the array contains two arrays, the first contains "a","b" and "c" and the second contains "1" and "2".
I want to have an array list in vba, hence I have a variant declared in excel vba like:
Dim Students(10) as variant
Now I want to store numbers in Students list. the numbers are not continuous. Sometime like:
Students(2,7,14,54,33,45,55,59,62,66,69)
How can I do this in vba? also how can I access the list items?
Students must be declared as a dynamic array. That is, an array whose bounds can be changed. Dim Students(10) gives an array whose bounds cannot be changed and cannot be loaded from an array.
Dim Students() As Variant
To load Students:
Students = Array(2,7,14,54,33,45,55,59,62,66,69)
To access the elements:
Dim Inx As Long
For Inx = LBound(Students) to UBound(Students)
Debug.Print Students(Inx)
Next
LBound (Lower bound) and UBound mean that the for loop adjusts to the actual number of elements in Students.
This is too complex for you right now, and you'll probably never run into a situation where you'll need this, but:
I use the following method for forming more memory-efficient arrays (because Variant uses the most memory of any variable type) while still having the convenience of declaring the array contents in one line. To follow your example:
Dim Students() As Long
Dim Array2() As String
Array2() = Split("2,7,14,54,33,45,55,59,62,66,69", ",")
ReDim Array1(0) As Long
For Loop1 = LBound(Array2()) To UBound(Array2())
ReDim Preserve Array1(0 To (UBound(Array1) + 1)) As String
Array1(Loop1) = Array2(Loop1)
Next Loop1
ReDim Preserve Array1(0 To (UBound(Array1) - 1)) As Long
Erase Array2
An example of accessing it would be something like:
For Loop1 = LBound(Students) to UBound(Students)
Msgbox Students(Loop1)
Next Loop1
I learned this from here: http://www.vbforums.com/showthread.php?669265-RESOLVED-VBA-Excel-Assigning-values-to-array-in-a-single-line&p=4116778&viewfull=1#post4116778
You can add values to an Array like this...
For i = 1 to 10
Students(i) = i
Next i
Or like this
Students = Array(2,7,14,54,33,45,55,59,62,66,69)
Then you can access the values in the same manor. Note if you use the second option you'll need to declare it as follows:
Dim Students() As Variant
Well,
That depends on how you would supply the values for the array, would you get the values from Worksheet.Range or from TextBox or ListBox , But basically the code would be something like that :
Dim students(10) as Integer
Dim Carrier as Integer
For i = LBound(students) To UBound(Students)
'some code to get the values you want to from whatever is your source
'then assign the value to Carrier
students(i)=Carrier
Next i
It is not good practice to dim an array as Variant when you certainly know that you are going to use integers only, as it will eat alot of memory that is not needed in the first place.
You also should be aware of the bounds of the numbers that are going to be assigned, if it exceeds the Integer limit then you should use Double or Float.
This is my first participation in the site,Cheers.
I know you can easily take a range of cells and slap them into a Variant Array but I want to work with a string array (because it's single-dimensional and takes less memory than a Variant array).
Is there any way to automatically convert a range into a string array?
Right now I am using a function that will take the range and save the values in a variant array, then convert the variant array to a string array. It works nice , but I'm looking for a way to go directly from the range to string array. Any help would be greatly appreciated.
Function RangeToArray(ByVal my_range As Range) As String()
Dim vArray As Variant
Dim sArray() As String
Dim i As Long
vArray = my_range.Value
ReDim sArray(1 To UBound(vArray))
For i = 1 To UBound(vArray)
sArray(i) = vArray(i, 1)
Next
RangeToArray = sArray()
End Function
UPDATE:
It's looking like there is no way to skip the step of throwing the data into a variable array first before converting it to a single-dimensional string array. A shame if it's true (even if it doesn't take much effort, I like to ultra-optimize so I was hoping there was a way to skip that step). I'll close the question in a few days if no solution presents itself. Thanks for the helpful comments, guys!
UPDATE2:
Answer goes to Simon who put in great effort (so did everyone else) and utlimately pointed out it's indeed impossible to go from range to string array in one shot. Thanks, everyone.
You actually can go directly from a range to an array using the functions Split, Join and a delimiter not in the text.
Assuming you have already assigned a 1D range of values as SrcRange
Dim Array() As String: Array = Split(Join(Application.Transpose(SrcRange), "#"), "#")
How about...
Public Function RangeToStringArray(theRange As Excel.Range) As String()
' Get values into a variant array
Dim variantValues As Variant
variantValues = theRange.Value
' Set up a string array for them
Dim stringValues() As String
ReDim stringValues(1 To UBound(variantValues, 1), 1 To UBound(variantValues, 2))
' Put them in there!
Dim columnCounter As Long, rowCounter As Long
For rowCounter = UBound(variantValues, 1) To 1 Step -1
For columnCounter = UBound(variantValues, 2) To 1 Step -1
stringValues(rowCounter, columnCounter) = CStr(variantValues(rowCounter, columnCounter))
Next columnCounter
Next rowCounter
' Return the string array
RangeToStringArray = stringValues
End Function
Function RangeToStringArray(myRange as range) as String()
ReDim strArray(myRange.Cells.Count - 1) As String
Dim idx As Long
Dim c As Range
For Each c In myRange
strArray(idx) = c.Text
idx = idx + 1
Next c
RangeToStringArray = strArray
End Function
If you don't mind altering the contents of the clipboard then:
COPY the range to the clipboard with the Copy method:
MyTargetRange.Copy
Copy the contents from the clipboard to a string variable (search this site or elsewhere for functions to transfer strings to/from the clipboard).
SPLIT the string into a variant array:
MyStringArray = Split(MyClipboardText, vbCrLf)
OPTIONAL: The array will have one additional blank element because there is always an additional Return (vbCrLf) at the end of the text you just copied to the clipboard. To remove simply resize the array:
Redim Preserve MyStringArray(Ubound(MyStringArray) - 1)
Very simple and quick!!!
Drawbacks are that the clipboard may change when you least expect it (during a recalculation) and that it only produces arrays of strings (not Doubles or other numerical value types).
This would be EXTREMELY HELPFUL if you are working with lots of repetitive functions (thousands) that use the same data (thousands of data points). The first time your function is called, do all the intermediate calculations on the ranges of data that you need but save the results in static variables. Also save a string copy of your input ranges via the clipboard. With each subsequent call to your function, convert the input ranges to text, again via the clipboard, and compare with the saved copy. If they are the same you may be able to bypass allot of your preliminary calculations.
Named ranges used in VBA are already arrays. So first make the range into a named range, then refer to it and delete the named range.
For example:
ThisWorkbook.Names.Add Name:="test_array", RefersTo:=Sheet1.Range("A4:B10")
a = Sheet1.Range("test_array")
ThisWorkbook.Names("test_array").Delete