I've worked this code over a few times, but I always seem to have a problem with the Split statement passing my array. Here's a piece of code that's not working and I can't figure out why
Private Sub parseCSV()
'Parse "Notes" column and return Moods/Keywords to their apropriate cells
Dim CSV As String
Dim fullArray() As String
Dim lRow As Long
Dim Keywords As String
Dim Moods As String
Dim i As Long
lRow = ActiveSheet().Range("BL" & ActiveSheet().Rows.Count).End(xlUp).Row
For i = 3 To lRow
CSV = ActiveSheet.Range("BL" & i)
fullArray() = Split(CSV, Chr(10))
ActiveSheet.Range("CE" & i).Value = fullArray(3)
ActiveSheet.Range("CD" & i).Value = fullArray(2)
Next i
End Sub
It gives an Err-9, value out of range. It's so weird. I've tested it a bunch of different ways and this is what I've found.
It will return the 1st piece of data in the array. I can change my delimiter to any thing i want and get exactly what I would expect in the first place of the array returned, if I change my code to fullArray(). I've also tried using Application.Index(fullArray, 1, 2), no dice. I've tried using various combination of array coordinates and variant/string combos. Nothing. Please help, I would greatly appreciate it.
Here is an example of what is contained in the cell being split;
To License Contact, licensing#primarywavemusic.com, 212.661.6990/310.247.8630
Go, White, Know
Happy, Rock, Upbeat, Catchy
You need to test the UBound first to verify there are actually 3 lines. A UBound(fullArray) of 2 indicates three lines. This is an example of a zero based array. The third line ends up in fullArray(2).
If your input is three lines long you can get the split using:
fullArray(0)
fullArray(1)
fullArray(2)
Here is your adjusted code:
For i = 3 To lRow
If UBound(fullArray) >= 2 Then
CSV = ActiveSheet.Range("BL" & i)
fullArray() = Split(CSV, Chr(10))
ActiveSheet.Range("CE" & i).Value = fullArray(2) 'enter third line
ActiveSheet.Range("CD" & i).Value = fullArray(1) 'enter second line
Else
'this will output the cell address of any cell that
'doesn't have 3 lines within the cell
Debug.Print ActiveSheet.Range("BL" & i).Address
End If
Next i
Related
I have a column full of data in a format I don't like, and need them in another format. Currently they are formatted like this: "190826_095630_3E_1 (ROI 0)" and I need just the "3E" portion. I have written a string split that uses the "_" and I figure I can then just take the column of data that is produced that I want, however I can only get this to work one cell at a time while I click each one. I tried to write a for loop but I am running into trouble, most likely because I used "active.cell". Does anyone have a better way to loop this split through my column? Alternatively if you also know how to just return the third string split (3E) I would really appreciate it.
'No loop: This works for one cell
Option Explicit
Sub NameTest()
Dim txt As String
Dim i As Integer
Dim FullName As Variant
txt = ActiveCell.Value
FullName = Split(txt, "_")
For i = 0 To UBound(FullName)
Cells(1, i + 1).Value = FullName(i)
Next i
End Sub
'Attempt at a loop:
Option Explicit
Sub NameTest()
Dim txt As String
Dim i As Integer
Dim FullName As Variant
Dim x As Integer
For x = 1 To 1000
txt = ActiveCell.Value
FullName = Split(txt, "_")
For i = 0 To UBound(FullName)
Cells(1, i + 1).Value = FullName(i)
Next i
Next x
End Sub
I would like to get this to run until the last cell with data in a given column.
So I have an array with a lot of data, I used to write the data to excel sheet via for cycle, but it took too long, so I looked into faster alternatives.
Now I try to display the information with setting a value of range of cells directly to array:
Sub displayRandomMatrix(clientsColl As Collection, resultWorkbook As Workbook)
Dim NamesRange As Range
With resultWorkbook.Worksheets("matrix_random")
...
Set NamesRange = _
.Range(.Cells(2, 1), .Cells(clientsColl.Count + 1, 1))
Dim NamesArray() As String
ReDim NamesArray(1 To clientsColl.Count)
Dim clientRow As Long
Dim simulation As Long
clientRow = 1
simulation = 1
Dim clientCopy As client
For Each clientCopy In clientsColl
For simulation = 1 To clientCopy.getRandomNumbers.Count
...
Next
NamesArray(clientRow) = clientCopy.getClientName
clientRow = clientRow + 1
Next
...
NamesRange.value = NamesArray
...
End With
'debugging
Debug.Print "**************start"
For clientRow = 1 To clientsColl.Count
Debug.Print NamesArray(clientRow)
Next
Debug.Print "**************end"
End Sub
However when I then open a resultWorkbook I see that the same client's name is written in all the needed cells of the 1st column. At the same the debug section of the code produces correct output - there are correct multiple clients names in that array.
So something gets broken when I assign that array to a range: NamesRange.value = NamesArray.
At the same time I do similar thing with other arrays and it works, but this while comes out with the bug.
What might be the reason?
NOTE: clientsColl is a good, correct collection of Clients. There is nothing wrong with it, neither is with resultWorkbook.
NamesArray is a horizontal array, which you are trying to assign to a vertical range. Try using Application.Transpose
NamesRange.value = Application.Transpose(NamesArray)
Transpose is a quick fix but has its limitations. So if that does not work you will need to force a vertical array by declaring a 2nd dimension in your array:
ReDim NamesArray(1 To clientsColl.Count, 1 to 1)
Then when you fill it make sure to include the second dimension:
NamesArray(clientRow,1) = clientCopy.getClientName
Then you can assign it as you have:
NamesRange.value = NamesArray
I am sorry if this sort of questions has already been asked, I couldn't find the answer I needed and I am quite new to VBA.
I am trying to match some values from one table to the other via an Index Match which is moving between 2 Workbooks. To do this properly I have used two loops For To. But my Code is really slow when it comes to a few thousands lines. Can I improve it with an Array or something else?
Dim mainWB As Workbook
Dim mainWS As Worksheet
Set mainWB = ActiveWorkbook
Set mainWS = mainWB.Sheets(1)
Dim RowsToProcess As Long
RowsToProcess = mainWS.Range("C" & Rows.Count).End(xlUp).Row
Dim lastCol As Long
lastCol = mainWS.Cells(10, Columns.Count).End(xlToLeft).Column
Range(Cells(11, 8), Cells(RowsToProcess, lastCol)).Select
Selection.NumberFormat = "General"
For i = 1 To lastCol
For a = 1 To RowsToProcess
If Workbooks("template.xls").Sheets("#").Cells(10 + a, 7 + i).Value <> vbNullString Then
Cells(10 + a, 7 + i).Select
ActiveCell.FormulaR1C1 = _
"= "Long Formula" "
End If
Next
Next
For my Long formula. It is basically doing 2 Index(Match. between this Workbook and 2 others, but I thought I would take it out here to keep it clearer
Thank you very much for the help!
If you are effectively defining a range you can use the first and last columns and rows addresses and create a range object.
See examples here: Dynamic ranges
You can then do:
Range(myRange).SpecialCells(xlCellTypeBlanks).FormulaR1C1 = "LongFormula"
which effectively replaces all blank cells with your formula without having to do all the loops.
Combine those steps with the items mentioned in the comments such as avoiding .select.
Summary:
Avoid the .select
Use WITH where possible when working with objects
Get the first cell address and last cell address and create your range object
Use the special cells method to set blanks in this range to your formula.
I have written a VB.NET application in Visual Studio 2015. (first time ever had any contact with visual basic or VS). The application takes an input csv file, analyses it and splits it according to that analysis into 2 output csv files. For one of these output files, I then need to change every blank cell to have the value of zero. My prob, is that the code i've made is processing 750 input csv files to produce 1500 output files and each process in the loop is taking 5 mins meaning it's taking up to 5 days to run!! That is too long!
I'm trying to work out how to make the code run quicker. One easy first step would be in the blank cell to zero operation as i'm currently doing it cell by cell. I read that better to do via an array but i'm unsure how to code it...Can someone help?
My code now is:
Dim forceDataRangeDest, cell As Excel.Range
Dim blank As String
Dim forceDataRow, lastDataRow As Integer
'copy force data from original workbook to sheet 1 of new workbook
If ws.Range("Z" & (forceLegRowStart + 1)).Value = "Force Plate 3" Then
forceDataRow = forceDataRow + 2
forceDataRangeSrc = ws.Range("Z" & forceDataRow & ":AK" & lastDataRow)
Else forceDataRangeSrc = ws.Range("A" & forceDataRow & ":M" & lastDataRow)
End If
wsData = wbForce.Sheets("Sheet1")
wsData.Name = "Data"
forceDataRangeDest = wsData.Range("A1")
forceDataRangeSrc.Copy(forceDataRangeDest)
'insert new column A if Force Plate 3 data is one taken for the time interval data of column A
If ws.Range("Z" & (forceLegRowStart + 1)).Value = "Force Plate 3" Then
wsData.Columns("A:A").Insert(1)
'write in the Data
forceDataRangeSrc = ws.Range("A" & forceDataRow & ":A" & lastDataRow)
forceDataRangeSrc.Copy(wsData.Range("A1"))
End If
forceDataRangeDest = wsData.Range("A1:M" & ((lastDataRow - forceDataRow) + 1))
For Each cell In forceDataRangeDest
blank = cell.Value
If String.IsNullOrWhiteSpace(blank) Then
cell.Value = 0
End If
Next
It is the For Each cell at the bottom of this sample code that i think is really increasing the process time...how would i write that as an array and then write array into excel in one go?
Many thanks for any help you can give.
You could use the Range.Find and Range.FindNext methods in VBA which would be quicker than looping through all the cells. Here's an example of the VBA code:
Sub FindEmptyCells()
Dim found As Range
Dim firstCell As String
Set found = ActiveSheet.UsedRange.Find(What:="", LookAt:=xlWhole)
firstCell = found.Address
Do While Not (found Is Nothing)
Debug.Print found.Address
Set found = ActiveSheet.UsedRange.FindNext(found)
If found.Address = firstCell Then
Exit Do
End If
Loop
End Sub
EDIT: Added the code to use OP's range object
Dim found As Range
Dim firstCell As String
Set found = forceDataRangeDest.Find(What:="", LookAt:=xlWhole)
firstCell = found.Address
Do While Not (found Is Nothing)
found.Value = 0
Set found = forceDataRangeDest.FindNext(found)
If found.Address = firstCell Then
Exit Do
End If
Loop
I have 2 sheets. I am using a user-defined function in sheet 1, in which I want to use an array to compare some strings. The array is comprised of the contents of a column of cells in the second sheet (which is named "phrases.").
So (looking at it another way) in "phrases" I have 100 strings typed into column P, cells 3 to 102. And I want to put all of them into an array that i can use later.
Now, let me complicate it a little - my intent is that users of the spreadsheet will be able to add new content to column P, so that it may eventually be 500 cells or more. So I really want to populate that array dynamically.
Here's where i am - and it doesn't seem to be working:
Dim newarray() As String
Dim i As Long
Dim counter As Long
counter = 0
For i = 0 To 5000
If Worksheets("phrases").Cells(i + 3, 16).Value <> 0 Then
newarray(counter) = Worksheets("phrases").Range(i + 3, 16).Value
counter = counter + 1
End If
Next
Where am i going wrong?
Please note - I've tried this without .Value - didn't seem to work.
I've tried this with .Text instead of .Value - didn't seem to work.
I've tried CStr(Worksheets("phrases").Range(i + 3, 16).Value) and several variations - and it didn't seem to work.
I expect there is something simple I am missing here - but i have no idea what.
Dim newarray() As String
Dim i As Long
Dim lr AS Long
Dim counter As Long
lr = ActiveSheet.Range("P" & Rows.Count).End(xlUp).Row
counter = 0
For i = 1 To lr
If Worksheets("phrases").Range("P" & i).value <> 0 Then
Redim Preserve newarray(counter)
newarray(counter) = Worksheets("phrases").Range("P" & i).value
counter = counter + 1
End If
Next
First construct a comma-separated string. Then convert the string into an array using the Split() function.
You can make the array directly from the cells without having to loop at all using a single line of code, this will also capture anything that the user adds to the bottom of column P by using the Resize() method:
Sub SO()
stringArray = [P3:P102].Resize(Range("P" & Rows.Count).End(xlUp).Row - 2, 1)
'// Print each value in the array
For Each x In stringArray
Debug.Print CStr(x)
Next x
End Sub