vb.net read arraylist to excel column of cells - vb.net

I'm trying to read values from one excel file to arraylists, then use this information to fill another arraylist. what I tried doing was this
For cellcount As Integer = 1 To buildList.Count
oSheet.Range(1, cellcount).Value = buildList(cellcount-1)
oSheet.Range(2, cellcount).Value = streamList(cellcount-1)
Next
and I'm getting an error "Exception from HRESULT: 0x800A03EC"
I can fill just a single cell by doing this
oSheet.Range("A7").Value = buildList(2)
oSheet.Range("B7").Value = streamList(2)
does anybody know a way to increment "A7" to A8, A9, A10, etc. same with B? or of a way to do this as if it were a 2D array? Thanks!

To fill a range, you need a two-dimensional object, even if the range is 1-dimensional.
The range should also be between two cells.
Here is an example assuming we have an array ArrayToAdd, and a cellcount (as you had).
Dim exObArray(ArrayToAdd.length- 1, 0) As Double
'go through the list and add values to objects (2d array)
For a As Integer = 0 To ArrayToAdd.length- 1 Step 1
exObArray(a, 0) = ArrayToAdd(a)
Next
oSheet.Range(oSheet.Cells(1, 0), oSheet.Cells(1, cellcount)).value = exObArray
I'm not sure that I have the range right, but you get the idea. This one goes from (1,0) to (1,cellcount)

got it working by concatenating the number as a variable after the letter and incrementing it each time, as below
For cellcount As Integer = 1 To buildList.Count
oSheet.Range("A" & cellcount + 9).Value = buildList(cellcount - 1)
oSheet.Range("B" & cellcount + 9).Value = streamList(cellcount - 1)
Next
working as I wanted now.

Related

VBA MIN and MAX function always returning 0

Hello I am trying to get the MIN and MAX values from the array and it always returns "0" despite anything. My code:
Dim MachineCapacitySmallestArray() As Variant
MachineCapacitySmallestArray = thisworkbook.worksheets(1).range("C25:D25")
SmallestCapacity = Application.Min(MachineCapacitySmallestArray)
in range I have natural numbers
I tried formatting those cells to numbers etc. but nothing works. What is the mistake I'm making and how to fix it?
According to the comments, it seems that your problem is your data, you have likely strings in your cell, not numbers (maybe somehow imported?)
As already mentioned, changing the cell format doesn't change the content of a cell, it just defines how to display data. The number 3.14 can be displayed as 3, as 3.140000, as 00003.14 or as 3.14E+00, nothing changes it's value. However, a String '3.14 is a combination of the characters 3, ., 1 and 4 and has nothing to do with a number. Setting a cell format after the value is in the cell will not convert it to a number.
If you read your data into VBA, VBA will get the exact values from Excel and in your case, you will have to convert it into numbers manually, for example with the following routine. The On Error Resume Next will prevent a type mismatch if a cell doesn't contain something that can be converted into a number.
Sub ArrToNumber(ByRef arr)
Dim i As Long, j As Long
For i = LBound(arr, 1) To UBound(arr, 1)
For j = LBound(arr, 2) To UBound(arr, 2)
On Error Resume Next
arr(i, j) = CDbl(arr(i, j))
On Error GoTo 0
Next
Next
End Sub
Now just add a call to this routine to your code. If you want to have the numbers also in Excel, remove the comment sign from the last statement.
Dim MachineCapacitySmallestArray() As Variant
MachineCapacitySmallestArray = thisworkbook.worksheets(1).range("C25:D25")
ArrToNumber MachineCapacitySmallestArray
SmallestCapacity = Application.Min(MachineCapacitySmallestArray)
' thisworkbook.worksheets(1).range("C25:D25") = MachineCapacitySmallestArray

Finding dates and storing ranges in variables

I'm trying to find "blocks" in the worksheet that have dates in the A-column. A block is seperated by lines as you can see from the picture. The whole file is full of these blocks but I only need the blocks that have dates in the A-column. Just to be clear I don't just need the rows with the dates but the full block that contains the date.
A block in my files for example is the Range A172:G192.
Picture of the file:
[![enter image description here][1]][1]
How should I continue after selecting the first block? I probably should use the Find function starting from row 184 or the row of ResultDown variable moving down the sheet on "A" Column. However the row needs to be dynamic, so I can use it for the next block. Also I have no idea how many blocks there will be, so I would like to hear from you how to solve this aswell.
I would like to save all the blocks as different variables and then hide all the blocks in the worksheet and then just unhide the blocks that I stored in the variables.
My biggest problem is the last row.
Result2 = Range(Cells(StartcellRow, 1), Cells(1000, 1)).Find(What:="**/**/****", After:=Range(Cells(StartcellRow, 1))).Select
I keep getting an runtime error 1004
Public Sub FB_MAKRO()
Dim FBwb As Workbook
Dim FBsht As Worksheet
Dim ACol As Range
'Set variables for workbook and sheet
Set FBwb = Workbooks.Open(Filename:="C:\Users\l000xxx\Desktop\Makrot\FORCED BALANCE MAKRO\FB HARJOITUS.xls")
Set FBsht = FBwb.Sheets("Forced Balance")
Set ACol = FBsht.Range("A1:A1000")
'I want ACol variable to be the entire A-Column. Any ideas?
'For some reason the range function is not working here?
'This locates the date in A'column, so I can select the correct block
Result = Range("A3:A1000").Find(What:="**/**/****", After:=Range("A3")).Address
'This is the top left corner of the Block1 selection
ResultUp = Range(Result).End(xlUp).Offset(-1, 0).Address
Range(ResultUp).End(xlDown).Select
Range(ActiveCell, ActiveCell).End(xlDown).Select
'The ResultsDownLastRow variable is for Block2 find function
'ResultDown is the bottom right corner of the Block1
ResultsDownLastRow = Range(ActiveCell, ActiveCell).End(xlDown).Address
ResultDown = Range(ActiveCell, ActiveCell).End(xlDown).Offset(-2, 6).Address
'First Block assigned. I plan to use this in the end when I hide everything and then unhide these blocks
Block1 = Range(ResultUp, ResultDown).Select
' NEXT BLOCK STARTS HERE
'StartCellRow is the cell that the find function should start looking for Block2
'Result2 is the find function for Block2
StartcellRow = Range(ResultsDownLastRow).Row
Result2 = Range(Cells(StartcellRow, 1), Cells(1000, 1)).Find(What:="**/**/****", After:=Range(Cells(StartcellRow, 1))).Select
End Sub
'This returns value 194
StartcellRow = Range(ResultsDownLastRow).Row MsgBox StartcellRow
'This should work but doesn't. I get a syntax error
Range(Cells(StartcellRow &","& 1),Cells(1000 & "," & 1)).Find(What:="**/**/****", After:=Range(Cells(StartcellRow& ","& 1)).Select
This doesn't work either
'StarcellRow gives out value of 194
StartcellRow = Range(ResultsDownLastRow).Row
Result2 = Range("A&:StartcellRow:A648").Find(What:="**/**/****", After:=Range("A&:StartcellRow")).Select
This doesn't give me a syntax error but it's not working
I would search for all currency header and store their rownumber into an array. For each rownumber in the array i would look into the cell below (rownumber + 1). when there is a date in the cell, i would set the range in the following way:
set rangeWithDate = Range(Cells(actualRowNumberInArray - 1, 1), Cells(nextRowNumberInArray - 2, 7))
Array:
Dim array1() As long
Redim array1(5)
For i = 1 To 5
array(i) = i
Next i
Redim array1(10) ' changes the "length" of the array, but deletes old entries
For i = 1 To 10
Feld1(i) = i
Next i
Redim Preserve array1(15) ' changes the "length" of the array without deleting old entries

VBA - check for duplicates while filling cells through a loop

I am writing a VBA code that goes through a defined matrix size and filling cells randomly within its limits.
I got the code here from a user on stackoverflow, but after testing it I realized that it does not fit for avoiding duplicate filling, and for instance when filling 5 cells, I could only see 4 cells filled, meaning that the random filling worked on a previously filled cell.
This is the code I'm working with:
Dim lRandom As Long
Dim sCells As String
Dim sRandom As String
Dim rMolecules As Range
Dim i As Integer, j As Integer
Dim lArea As Long
lArea = 400 '20x20
'Populate string of cells that make up the container so they can be chosen at random
For i = 1 To 20
For j = 1 To 20
sCells = sCells & "|" & Cells(i, j).Address
Next j
Next i
sCells = sCells & "|"
'Color the molecules at random
For i = 1 To WorksheetFunction.Min(5, lArea)
Randomize
lRandom = Int(Rnd() * 400) + 1
sRandom = Split(sCells, "|")(lRandom)
Select Case (i = 1)
Case True: Set rMolecules = Range(sRandom)
Case Else: Set rMolecules = Union(rMolecules, Range(Split(sCells, "|")(lRandom)))
End Select
sCells = Replace(sCells, "|" & sRandom & "|", "|")
lArea = lArea - 1
Next i
rMolecules.Interior.ColorIndex = 5
Using this same exact code which works perfectly, WHAT can I insert and WHERE do I do that so that the code would check if a cell is previously already filled with a string or a color?
I feel as though this code I'm looking for should be right before
rMolecules.Interior.ColorIndex = 5
But I'm not sure what to type.
EDIT
From the comments I realized that I should be more specific.
I am trying to randomly fill cells with the blue color (.ColorIndex = 5), but what I need to check first is if the randomizing hadn't marked a cell twice, so that for instance in this case, if I want to mark 5 different cells, it marks only 4 of them because of a duplicate and thus fills only 4 cells with the blue color. I need to avoid that and make it choose another cell to mark/fill.
I'd appreciate your help.
Keep the cells you use in a Collection and remove them as you fill the random cells:
Sub FillRandomCells(targetRange As Range, numberOfCells As Long)
' populate collection of unique cells
Dim c As Range
Dim targetCells As New Collection
' make sure arguments make sense
If numberOfCells > targetRange.Cells.Count Then
Err.Raise vbObjectError, "FillRandomCells()", _
"Number of cells to be changed can not exceed number of cells in range"
End If
For Each c In targetRange.Cells
targetCells.Add c
Next
' now pick random 5
Dim i As Long, randomIndex As Long
Dim upperbound As Long
Dim lowerbound As Long
For i = 1 To numberOfCells
lowerbound = 1 ' collections start with 1
upperbound = targetCells.Count ' changes as we are removing cells we used
randomIndex = Int((upperbound - lowerbound + 1) * Rnd + lowerbound)
Set c = targetCells(randomIndex)
targetCells.Remove randomIndex ' remove so we don't use it again!
c.Interior.Color = 5 ' do what you need to do here
Next
End Sub
Sub testFillRandomCells()
FillRandomCells ActiveSheet.[a1:t20], 5
FillRandomCells ActiveSheet.[b25:f30], 3
End Sub
EDIT: Changed to make the target range and number of changed cells configurable as arguments to a function. Also added error checking (always do that!).
Why not build a list of random numbers and place in a Scripting.Dictionary, one can use the Dictionary's Exist method to detect duplicates, loop through until you have enough then you can enter your colouring code confident that you have a unique list.

Subscript out of range when filling data in string array

I'm trying to store some reference data in a string array and then use that later on to compare with another string array. However, the code is not working since I'm getting a "subscript out of range" error (see code comment below).
Sub StoreBaseReferences()
Dim cell As Range
Dim val As Variant
Dim stringValues() As String
Dim i, rowCounter, columnCounter As Integer
rowCounter = 0
columnCounter = 0
For i = 2 To Sheets("sheet").UsedRange.rows.Count
For Each cell In Range(Cells(i, 2), Cells(i, 4))
stringValues(rowCounter, columnCounter) = cell.Value 'this is throwing the subscript ouf of range error
columnCounter = columnCounter + 1
Next cell
rowCounter = rowCounter + 1
columnCounter = 0
Next i
MsgBox (stringValues(0, 0))
End Sub
What is missing here?
Arrays in VBA need to be dimensioned with the number of elements that are expected to be used. You've defined the dimension, but not specified how many elements will be added to it. Try adding the following line just before the For loop:
ReDim stringValues(Sheets("sheet").UsedRange.Rows.Count, 3)
you are declaring a 1d array Dim stringValues() As String
but trying to use it as a 2d array stringValues(rowCounter, columnCounter)
Also, you are not declaring the size of the array and you are trying to use it. In VBA you have to make sure you tell the size of the array at the declaration time.
To delcare the count of elements that the array is capable of storing
Dim stringArray(0 to 10) or Dim stringArray(10)
and when iterating the counter starts at 0.
Using ReDim stringValues() allows you to resize the bounds at a later stage.
The topic is too broad to go over in one answer so check out the links to learn out how to dimension your array
VBA arrays
Array in Excel VBA

Interpreting VBA code for moving averages

While I roughly understood my coding at the time of writing it awhile back, I have since forgotten how to interpret the first few parts of it (in bold).
Why 'as long'? My understanding is that this is used when the variable is only to take larger integer values. Since the share values contain several decimals, I am not sure why I chose this over 'double'.
Why/when do we dim a variable as a 'range', and why do we use 'set' at all? My limited understanding of the purpose of the set function is to assign values to 'object' variables. Why is the 'range' an 'object'?
I have completely forgot what the line Set stockValue = Range("B5:B" & lastStockprice) is doing, especially the ampersand.
I've no idea what is going on here:
ReDim stockPrice(stockValue.Count - 1)
For Each cell In stockValue
stockPrice(cell.Row - 5) = cell.Value
Next
Sub MovingAverage()
Dim CumulSum() As Double
Dim MovingAv() As Double
RowCountA = Range("StockPrice").Rows.Count
RowCountB = Range("MovingAv").Rows.Count
ReDim CumulSum(RowCountB)
Dim stockPrice As Variant
Dim lastStockprice **As Long**
lastStockprice = Cells(Rows.Count, "B").End(xlUp).Row
Dim stockValue **As Range**
**Set stockValue = Range("B5:B" & lastStockprice)**
**ReDim stockPrice(stockValue.Count - 1)
For Each cell In stockValue
stockPrice(cell.Row - 5) = cell.Value
Next**
For i = 0 To RowCountB - 1
For k = 0 To 9
CumulSum(i) = CumulSum(i) + stockPrice(i + k)
Next k
Next i
For i = 1 To RowCountB
Range("MovingAv").Cells(i) = CumulSum(i - 1) / 10
Next i
End Sub
If someone could please explain the bolded code for me (I've a very basic knowledge of VBA that extends about as far as matrix multiplication, basic functions and double arrays), it would be greatly appreciated. :)
Dim lastStockprice **As Long**
lastStockprice = Cells(Rows.Count, "B").End(xlUp).Row
This has to be long because we are trying to find the last row in Col B. This is to make the code compatible with xl2007+ (Where there are 1048576 rows). You can see this link on how to get the last row.
Why is the 'range' an 'object'?
See this link. Also see this.
I have completely forgot what the line Set stockValue = Range("B5:B" & lastStockprice) is doing, especially the ampersand.
As mentioned earlier lastStockprice is the last row and & is used to concatenate so that we can set our range. Let's say the last row is 20 then the above code can be written as
Set stockValue = Range("B5:B" & 20)
'OR
Set stockValue = Range("B5:B20")
I've no idea what is going on here: ReDim stockPrice(stockValue.Count - 1)
What the code is trying to do is dynamically increase the size of the array so that it can store more values to it. REDIM (Re-Dimension) I would recommend seeing this link
FOLLOWUP (From comments)
I understand all of it now except this part: For Each cell In stockValue stockPrice(cell.Row - 5) = cell.Value Next**
What that piece of code is doing is looping through every cell in the range stockvalue and then storing the cell value in the array stockPrice
Ex: Let's say we have a range, A1:B2
When we say For each cell in Range("A1:B2"), we are telling the code to loop through every cell in that range (A1, A2, B1, B2)