send array to csv file - simulation too slow - arrays

I automated a montecarlo simulation for stock and option prices that runs 10 thousand paths for 606 trading days. All and all it works fine, the problem is that is slow. The slow part of the code is when it has to write an array of say 400 x 10000 to the spreadsheet, then export it into a new CSV file and save it.
It does this for a 25 option portfolio (it takes 1 minute per option.) So overall it takes 25 minutes, which is unacceptable. How can I write directly to CSV the arrays of data that I am filling with the simulation? I need to keep all stock prices, option prices and total portfolio value. Below is the code that I have created for this.
Sub Background_simulation()
0 Application.ScreenUpdating = False
1 Windows("Option Portfolio Simulation v7.xlsm").Activate
2 Sheets("Export").Activate
3 Dim Arr() As Variant
4 ArrStock = Range("F11:NTU616")
6 ArrOption = Range("F621:NTU1226")
7 Sheets("Export").Activate
8 Dim DestinationStock As Range
9 Set DestinationStock = Range("F11")
10 Dim DestinationOption As Range
11 Set DestinationOption = Range("F621")
12 Dim RAND(1 To 606, 1 To 10000) As Variant
13 Paths = Range("D6").Value
15 Dim Option_Paths(1 To 606, 1 To 10000) As Variant
16 Dim St_Paths(1 To 606, 1 To 10000) As Variant
17 Dim Options_Total(1 To 606, 1 To 10000) As Variant
18 FromOption = Range("D7").Value
19 UpToOption = Range("D8").Value
20 Sheets("Portfolio").Select
21 Let MaxExpirationOfSet = Application.WorksheetFunction.Max(Range("BC2:BC26").Value)
22 Sheets("Export").Select
23 For a = 2 To 606
24 For b = 1 To Paths
25 Randomize
26 RAND(a, b) = Application.WorksheetFunction.NormInv(RND(), 0, 1)
27 Next
28 Next
31 For Option_Nr = FromOption To UpToOption
32 Sheets("Export").Select
33 Range("F11:NTU616").Select
34 Selection.ClearContents
35 Range("F621:NTU1226").Select
36 Selection.ClearContents
38 Range("B1").Select
39 ActiveCell.FormulaR1C1 = Option_Nr
42 Calls = Range("L3").Value
43 If Calls = 0 Then GoTo 2010
44 St = Range("G2").Value
45 Rf = Range("G3").Value
46 Sigma = Range("G4").Value
47 dt = 1 / 250
48 mrn = Rf - (1 / 2) * Sigma ^ 2
49 X = Range("L5").Value
50 Expiration_Date = Range("D4").Value
120 For b = 1 To Paths
130 RAND(1, b) = 1
140 St_Paths(1, b) = St
150 Option_Paths(1, b) = Application.WorksheetFunction.Max(St - X, 0) * Calls
160 Options_Total(1, b) = Options_Total(1, b) + Option_Paths(1, b)
170 Next
190 For a = 2 To Expiration_Date
200 For b = 1 To Paths
600 St_Paths(a, b) = St_Paths(a - 1, b) * Exp(mrn * dt + Sigma * (dt) ^ (1 / 2) * RAND(a, b))
700 Option_Paths(a, b) = Application.WorksheetFunction.Max(St_Paths(a, b) - X, 0) * Calls
701 Options_Total(a, b) = Options_Total(a, b) + Option_Paths(a, b)
703 Next
704 Next
705 For a = (Expiration_Date + 1) To MaxExpirationOfSet
706 For b = 1 To Paths
707 St_Paths(a, b) = St_Paths(a - 1, b)
710 Option_Paths(a, b) = Option_Paths(a - 1, b)
711 Options_Total(a, b) = Options_Total(a - 1, b)
712 Next
730 Next
740 Sheets("Export").Select
750 Range("F11:NTU616").Select
760 Selection.ClearContents
770 Range("F621:NTU1226").Select
780 Selection.ClearContents
790 Range("A1").Select
800 DestinationStock.Resize(UBound(ArrStock, 1), UBound(ArrStock, 2)).Value = St_Paths
810 DestinationOption.Resize(UBound(ArrOption, 1), UBound(ArrOption, 2)).Value = Option_Paths
830 Sheets("Export").Copy
840 Range("F620").Select
845 ActiveWorkbook.BreakLink Name:= _
"C:\Users\pmesples\Desktop\Options\Option Portfolio Simulation v7.xlsm", Type _
:=xlExcelLinks
850 ChDir "C:\Users\pmesples\Desktop\Options"
860 ActiveWorkbook.SaveAs Filename:="C:\Users\pmesples\Desktop\Options\" & Option_Nr & ".csv", _
FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
900 ActiveWindow.Close
1000 Sheets("Export").Select
1001 Range("F" & 620 + MaxExpirationOfSet & ":NTU" & 620 + MaxExpirationOfSet).Select
1002 Selection.Copy
1003 Sheets("Results").Select
1004 Cells(5, Option_Nr + 3).Select
1005 Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=True
1006 Sheets("Export").Select
1010 Range("F11").Select
1020 Range(Selection, Selection.End(xlToRight)).Select
1030 Range(Selection, Selection.End(xlDown)).Select
1040 Selection.ClearContents
1050 Selection.End(xlDown).Select
1060 Range("F621").Select
1080 Range(Selection, Selection.End(xlDown)).Select
1090 Range(Selection, Selection.End(xlToRight)).Select
2000 Selection.ClearContents
2005 Range("A1").Select
2010 Next
2015 Range("B1").Select
2016 ActiveCell.FormulaR1C1 = 26
2020 DestinationOption.Resize(UBound(ArrOption, 1), UBound(ArrOption, 2)).Value = Options_Total
2030 Sheets("Export").Copy
2040 Range("F620").Select
2045 ActiveWorkbook.BreakLink Name:= _
"C:\Users\pmesples\Desktop\Options\Option Portfolio Simulation v7.xlsm", Type _
:=xlExcelLinks
2050 ChDir "C:\Users\pmesples\Desktop\Options"
2060 ActiveWorkbook.SaveAs Filename:="C:\Users\pmesples\Desktop\Options\26.csv", _
FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
2100 ActiveWindow.Close
2110 Sheets("Export").Select
2215 Range("B1").Select
2120 ActiveCell.FormulaR1C1 = 1
End Sub

You could probably get rid of selects and selections to speed up the macro, like:
32 Sheets("Export").Select
33 Range("F11:NTU616").Select
34 Selection.ClearContents
could be replaces by
32 Sheets("Export").Range("F11:NTU616").ClearContents
but you probably lost most of valuable seconds while saving file, as you already have noticed. Indeed, you could try export to file, see my subroutine:
Private Sub PrintToCSV(sFileName As String, rng As Range)
Dim TextFile As Integer
Dim FilePath As String
Dim FileContent As String
Dim cl As Range
FilePath = ThisWorkbook.Path & "\something something\" & sFileName & ".csv"
TextFile = FreeFile
Open FilePath For Output As TextFile
For Each cl In rng
Print #TextFile, cl.Value
Next cl
Close TextFile
End Sub
But, generally speaking, VBA is scripting language, so it is slow. I am not sure if writing to file will be faster than saving as, but you may try.

Related

How create dynamic arrays to loop through a list and sum up values based on a criteria

Below I have a list of “ID” numbers with their associated “Number “and their “values”. I am trying to create sub function that crates a dynamic array that collects all the “Values” that have a “Number” that is equal to and lesser than 30. After the array is filled it is summed and placed under the heading titled “30 or less”. I have been trying do this using VBA with no luck. I have read a bunch of posts and documents telling me how to do this but I can’t make sense of it. Could someone show me how to get this done. Its driving me crazy and I am sure its simple I eventually want to expand this to do the same with “Numbers ” that are greater than 30 but less than 60 and so on. Thank you
ID Number Value
0 60 100
1 31 101
2 12 102
3 30 103
4 21 104
5 60 105
30 or less
Try pasting this into a new module in VB.
This presumes that your Raw data is in Sheet(1) and sorted data will be in a new blank worksheet Sheet(2)
Sub AddNumbers()
Dim RowNo, ColNo As Long
'Skip Header Row
RowNo = 2
Do Until Sheets(1).Cells(RowNo, 1) = ""
If Sheets(1).Cells(RowNo, 2) <= 30 Then
Sheets(2).Cells(1, 1) = "30 or less"
ColNo = 1
Sheets(2).Cells((Sheets(2).Cells(Rows.Count, 1).End(xlUp).row + 1), ColNo) = Sheets(1).Cells(RowNo, 3)
ElseIf Sheets(1).Cells(RowNo, 2) > 30 And Sheets(1).Cells(RowNo, 2) <= 60 Then
Sheets(2).Cells(1, 2) = "Between 30 and 60"
ColNo = 2
Sheets(2).Cells((Sheets(2).Cells(Rows.Count, 2).End(xlUp).row + 1), ColNo) = Sheets(1).Cells(RowNo, 3)
ElseIf Sheets(1).Cells(RowNo, 2) > 60 And Sheets(1).Cells(RowNo, 2) <= 90 Then
Sheets(2).Cells(1, 3) = "Between 60 and 90"
ColNo = 3
Sheets(2).Cells((Sheets(2).Cells(Rows.Count, 3).End(xlUp).row + 1), ColNo) = Sheets(1).Cells(RowNo, 3)
End If
RowNo = RowNo + 1
Loop
' Add Subtotals
ColNo = 1
Do Until Sheets(2).Cells(1, ColNo) = ""
Sheets(2).Cells((Sheets(2).Cells(Rows.Count, ColNo).End(xlUp).row + 1), ColNo).Formula = "=SUM(" & Col_Letter(ColNo) & "2:" & Col_Letter(ColNo) & (Sheets(2).Cells(Rows.Count, ColNo).End(xlUp).row) & ")"
Sheets(2).Cells((Sheets(2).Cells(Rows.Count, ColNo).End(xlUp).row), ColNo).Font.Bold = True
ColNo = ColNo + 1
Loop
End Sub
Function Col_Letter(lngCol As Long) As String
Dim vArr
vArr = Split(Cells(1, lngCol).Address(True, False), "$")
Col_Letter = vArr(0)
End Function

How to sum values in array from different columns + EXCEL VBA

I need to calculate this in excel vba ,using array loop only :
round 0 round 1
9 28
65 84
28 47
84 103
41 60
66 85
115 134
I need to sum values in round 0 in loop so the sum result (408) must be divided by 7 , if not I WANT to sum one value from the round 1 (in this case 84 instead of 65 ) to the rest of values in round 0 so the sum result can divided by 7 . There will be so many round up to 7 . I need VBA code to accomplish this..
Notes :
round 0 and round 1 all in one two-dimensional array
My Question is : is there a way to sum values from different columns in multi-dimensional array ??
there is an image attached .
I appreciate any help or idea .
Thanks in advance
Excel VBA Array Model:
http://im56.gulfup.com/8rDErI.png
Here an example file contains macro "Question1.xlsm"
http://www.gulfup.com/?TKAAYM
Notes : click the link under the big green down arrow to download the file.
UPDATE :
here another macro to the file "Question1.xlsm" :
Sub A1()
Dim arrTemp1() As Integer
Dim sum1 As Integer
arrblkTable1 = Sheets("Sheet1").Range("blkTable1").Value
ReDim Preserve arrTemp1(0 To 1, 1 To 7)
For a = 0 To 1
sum1 = 0
For c = 1 To 7
arrTemp1(a, c) = arrblkTable1(c, 1) + (a * 19)
text6 = text6 & arrTemp1(a, c) & vbCrLf
Worksheets("TEST3").Cells(a + 1, c).Value = arrTemp1(a, c)
sum1 = sum1 + arrTemp1(a, c)
Next c
If XLMod(sum1, 7) = 0 Then
MsgBox "Yes " & sum1
Else
MsgBox "No " & sum1
End If
Next a
MsgBox text6
End Sub
Function XLMod(a, b)
' This replicates the Excel MOD function
XLMod = a - b * Int(a / b)
End Function
UPDATE : here a new update to the previous macro :
Sub A1()
Dim arrTemp1(), arrTemp2(), arrSUMs() As Integer
Dim sum1 As Integer
arrblkTable1 = Sheets("Sheet1").Range("blkTable1").Value
arrblkTable2 = Sheets("Sheet1").Range("blkTable2").Value
'-------------------------------- arrTemp1 ------------------------------
ReDim Preserve arrTemp1(0 To 1, 1 To 7)
For a = 0 To 1
sum1 = 0
For c = 1 To 7
arrTemp1(a, c) = arrblkTable1(c, 1) + (a * 19)
text6 = text6 & arrTemp1(a, c) & vbCrLf
Worksheets("TEST3").Cells(a + 1, c).Value = arrTemp1(a, c)
sum1 = sum1 + arrTemp1(a, c)
Next c
If XLMod(sum1, 7) = 0 Then
MsgBox "Yes " & sum1
Else
MsgBox "No " & sum1
For c = 1 To 7
sum1 = sum1 - arrTemp1(a, c)
arrTemp1(a, c) = arrblkTable1(c, 1) + ((a + 1) * 19)
sum1 = sum1 + arrTemp1(a, c)
If XLMod(sum1, 7) = 0 Then
MsgBox "Yes " & sum1 & " " & arrTemp1(a, c)
End If
Next c
End If
Next a
For x = 0 To UBound(arrTemp1)
For y = 1 To UBound(arrTemp1)
text7 = text7 & arrTemp1(x, y) & vbCrLf
Next y
Next x
MsgBox text7
End Sub
Function XLMod(a, b)
' This replicates the Excel MOD function
XLMod = a - b * Int(a / b)
End Function
I need now to put each sum1 in one array , how I can do that ??
If I understood it correctly you want something similar to this:
Sub p()
v = Range("A2:A8")
v1 = Sheets("Sheet1").Range("B2:B8")
s = Application.WorksheetFunction.Sum(v)
b = False
Count = 0
For i = 1 To 7
temp = v
temp(i, 1) = v1(i, 1)
s = Application.WorksheetFunction.Sum(temp)
b = s Mod 7 = 0
If b = True Then
Count = Count + 1
End If
Next
MsgBox Count
End Sub
It may help tremendously if you can give more detail about what problem you're trying to solve, instead of focusing on how to solve it this way. There is a possibility that there's another way of doing it that hasn't occurred to you that will be much simpler.
This isn't an answer. Yet. But it will take more space than is allowed in a comment to ensure we've got this right.
For your sample data:
round 0 round 1
9 28
65 84
28 47
84 103
41 60
66 85
115 134
You want to:
Sum all the values in Round 0 (9 + 65 + 28 + 84 + 41 + 66 + 115) = 408
Take that sum (408) mod 7 and see if the result is 0
408 / 7 = 58.28, so (408 mod 7) <> 0
If the result isn't 0 (as in this case)
Start substituting numbers from round 1 for numbers in Round 0
Sum (28 + 65 + 28 + 84 + 41 + 66 + 115) = 427
427 / 7 = 61 (427 mod 7) = 0
This is now your valid result set.
Had the first number in Round 1 been 29
Sum (29 + 65 + 28 + 84 + 41 + 66 + 115) = 428
428 / 7 = 61.14 so (428 mod 7) <> 0
Substitute the next number from round 1 for the next number from round 0
Sum (9 + 84 + 28 + 84 + 41 + 66 + 115) = 427
This is now your valid result set.
Is that the logic you're after?
What happens if you get to the end of round 1 and you don't find a total that (mod 7 = 0)?

Copy-paste loop with skipped values in VBA

I am fairly new to code-writing in general and VBA in particular.
I have tried to write a fairly simple macro that copies values from one cell to another on a daily basis, however I am wondering if there is a way to have fewer variables for the loop counters, in other words, can a loop counter skip certain values?
Private Sub YesButton_Click()
Dim z As Integer
Dim z1 As Integer
Dim z2 As Integer
Dim z3 As Integer
Dim z4 As Integer
Dim z5 As Integer
Dim z6 As Integer
Dim z7 As Integer
Dim z8 As Integer
Dim z9 As Integer
Dim z10 As Integer
Dim z11 As Integer
Dim z12 As Integer
Dim z13 As Integer
Application.Calculation = xlCalculationManual 'turn off autocalc to speed up copy paste process
For z = 5 To 16
Sheet68.Range("H" & z) = Sheet68.Range("D" & z).Value
Next z
For z1 = 21 To 33
Sheet68.Range("H" & z1) = Sheet68.Range("D" & z1).Value
Next z1
For z2 = 38 To 51
Sheet68.Range("H" & z2) = Sheet68.Range("D" & z2).Value
Next z2
For z3 = 73 To 86
Sheet68.Range("H" & z3) = Sheet68.Range("D" & z3).Value
Next z3
For z4 = 92 To 94
Sheet68.Range("G" & z4) = Sheet68.Range("D" & z4).Value
Next z4
For z5 = 100 To 110
Sheet68.Range("G" & z5) = Sheet68.Range("D" & z5).Value
Next z5
For z6 = 115 To 126
Sheet68.Range("G" & z6) = Sheet68.Range("D" & z6).Value
Next z6
For z7 = 131 To 142
Sheet68.Range("G" & z7) = Sheet68.Range("D" & z7).Value
Next z7
For z8 = 149 To 151
Sheet68.Range("G" & z8) = Sheet68.Range("D" & z8).Value
Next z8
For z11 = 157 To 164
Sheet68.Range("G" & z11) = Sheet68.Range("D" & z11).Value
Next z11
For z9 = 169 To 175
Sheet68.Range("G" & z9) = Sheet68.Range("D" & z9).Value
Next z9
For z10 = 180 To 186
Sheet68.Range("G" & z10) = Sheet68.Range("D" & z10).Value
Next z10
For z12 = 191 To 203
Sheet68.Range("H" & z12) = Sheet68.Range("D" & z12).Value
Next z12
Application.Calculation = xlCalculationAutomatic 'turn autocalc back on
Unload Me
End Sub
Thanks in advance
Here's an example of how you could re-think your code. You will clearly need to readapt the sample to your own data.
Declare a vector of ranges
The size of it, as many as your intervals are (I counted 14 in your case, but I might be wrong).
Dim ranges(1 To 5)
Dim j As Integer '<-- counter of the ranges
Dim k As Long '<-- counter of your loop
Define your ranges
Here you define, as strings, your specific ranges. In my example I've put random numbers, but in your case should be "5-16", "21-23" etc.
ranges(1) = "1-2"
ranges(2) = "5-10"
ranges(3) = "15-20"
ranges(4) = "25-30"
ranges(5) = "35-40"
Nest two loops
The outside one will loop through the ranges, the inside one will split the ranges and use the lower and upper bounds to loop through your cells
For j = 1 To 5
For k = Split(ranges(j), "-")(0) To Split(ranges(j), "-")(1)
'your code here
'test it with a msgbox:
MsgBox "k is now equal to " & k
Next k
Next j
To sum up
Your code should look something like this:
Dim ranges(1 To 14) '<-- not sure, please check it first!
Dim j As Integer, k As Long
ranges(1) = "5-16"
ranges(2) = "21-33"
'....
ranges(14) = "191-203"
For j = 1 To 14
For k = Split(ranges(j),"-")(0) To Split(ranges(j),"-")(1)
Sheet68.Range("G" & k) = Sheet68.Range("D" & k).Value
Next k
Next j
You can just declare 1 int and use it for every loop. U give it a new value at the start of the loop anyway!
So:
Dim z As Integer
For z = 0 To 10 Step 1
//Do something
Next
For z = 11 To 21 Step 1
//Do something
Next
Sub YesButton_Click()
Dim rngTemp As Range
For Each rngTemp In Range("H5:H16, H21:H33, H38:H51, H73:H86, H191:H203")
rngTemp.Value = rngTemp.Offset(, -4).Value
Next rngTemp
For Each rngTemp In Range("G92:G94, G100:G110, G115:G126, G131:G142, G149:G151, G157:G164, G169:G175, G180:G186")
rngTemp.Value = rngTemp.Offset(, -3).Value
Next rngTemp
End Sub

Find row number in column and move data Excel vba

I hope you guys can help me. I have an Excel sheet with data that I want to copy some some values and move them to another column.
The data currently is something like this:
A B
...
20:00:00 2456
21:00:00 2147
22:00:00 5623
23:00:00 1247
00:00:00 3549
01:00:00 1234
...
I have data from several days, and when I found the string "00:00:00" which is the beginning of another day, I want to copy the prior 24 values to the next column.
The result should be something like this:
A B C D
...
20:00:00 2456
21:00:00 2147
22:00:00 5623
23:00:00 1247
00:00:00 3549
01:00:00 1234
...
22:00:00 2418
23:00:00 3245
00:00:00 3549
01:00:00 5437
I've started to try found the row number of the values equal to "00:00:00", save them in an array and then make the difference between row value(i+1) "00:00:00" and row value(i) "00:00:00"
Thanks and regards,
Daniel Duarte
this has been tested just now:
Sub move()
Dim column As Integer
column = 3
For i = 1 To Cells(Rows.Count, 1).End(xlUp).Row
If Cells(i + 1, 1).Value > Cells(i, 1).Value and Cells(i + 1, 1).Value <> "" Then
Cells(i, column).Value = Cells(i, 2).Value
Cells(i, 2).Value = ""
Else
column = column + 1
Cells(i, column).Value = Cells(i, 2).Value
Cells(i, 2).Value = ""
End If
Next
End Sub
one caveat in this is the case that it is checking if the next hour is less than current, i.e. hour goes back to zero at midnight and it increases the column where it pastes too. It will work for any times within 24 hours window, irrelevant from minutes/seconds
You made a mention of the '24', so I thought it was 24 elements consistently. Is the timing consistent, or variable?
The solution in VBA is below.
Given something like this:
time value
20:00 100
21:00 200
22:00 300
23:00 400
0:00 500
1:00 600
2:00 700
3:00 800
4:00 900
5:00 1000
6:00 1100
7:00 1200
8:00 1300
9:00 1400
10:00 1500
11:00 1600
12:00 1700
13:00 1800
14:00 1900
15:00 2000
16:00 2100
17:00 2200
18:00 2300
19:00 2400
20:00 2500
21:00 2600
22:00 2700
23:00 2800
0:00 2900
1:00 3000
2:00 3100
3:00 3200
4:00 3300
5:00 3400
6:00 3500
7:00 3600
8:00 3700
9:00 3800
10:00 3900
11:00 4000
12:00 4100
13:00 4200
14:00 4300
15:00 4400
16:00 4500
17:00 4600
18:00 4700
19:00 4800
20:00 4900
21:00 5000
22:00 5100
23:00 5200
Is this what you are looking for?
Option Explicit
Sub shift()
Dim Test As String
Dim NumRows As Integer
Dim CurrentRow As Integer
Dim ToCopy As String
Dim x As Integer
Dim i As Integer
' Set numrows = number of rows of data.
NumRows = Range("A2", Range("A2").End(xlDown)).Rows.Count
' loop around
For x = 0 To NumRows - 1
Range("A2").Offset(x, 0).Select
Test = ActiveCell.Text
If Val(Test) = 0 Then
CurrentRow = ActiveCell.Row
If ((CurrentRow - 24) > 1) Then
For i = 1 To 24
If ((CurrentRow - i - 24) > 0) Then
ToCopy = ActiveCell.Offset(-i - 24 + 1, 1).Text
ActiveCell.Offset(-i + 1, 2).Value = ToCopy
End If
Next i
End If
Else
End If
Next
End Sub
Modifying this for the arbitrary case; for example, with time differences of 0:15.
This is a bit wordy/pendantic, but gives you the idea.
Option Explicit
Sub shift_arb()
Dim Test As String
Dim StartRow As Integer
Dim EndRow As Integer
Dim NumRows As Integer
Dim nZeroRows As Integer
Dim CurrentRow As Integer
Dim ToCopy As String
Dim x As Integer
Dim i As Integer
' Set numrows = number of rows of data.
NumRows = Range("A2", Range("A2").End(xlDown)).Rows.Count
' Establish "For" loop to loop "numrows" number of times.
For x = 0 To NumRows - 1
Range("A2").Offset(x, 0).Select
Test = ActiveCell.Text
' If we meet the critera; store the row values of the zero rows
If TimeValue(Test) = "12:00:00 AM" Then
nZeroRows = nZeroRows + 1
StartRow = EndRow
EndRow = ActiveCell.Row
' Only do this if you've hit the second zero row
' After this, we have to backfill the first, since we don't know the
' gap between the zeros
If (nZeroRows > 1) Then
' Go from one zero row to the next
For i = 0 To (EndRow - StartRow)
If ((StartRow - i) > 1) Then
ToCopy = Cells(StartRow - i, 2).Text
Cells(EndRow - i, 3).Value = ToCopy
End If
Next i
End If
End If
Next x
' At the end, cleanup, and do the rest.
Debug.Print StartRow, EndRow, ActiveCell.Row
For i = 0 To (EndRow - StartRow)
If ((i + EndRow - 1) < ActiveCell.Row) Then
ToCopy = Cells(StartRow + i, 2).Text
Cells(EndRow + i, 3).Value = ToCopy
End If
Next i
End Sub

Sort multidimensional array in VBScript

How can I "Sort" the multidimensional arrays based on the hole size parameter please?
eg: A simple example would be (Loaded from Text file):
> Liv1.HoleSize[0] = 22 Liv1.HoleX[0] = 250 Liv1.HoleY[0] = -55
> Liv1.HoleSize[1] = 14 Liv1.HoleX[1] = 750 Liv1.HoleY[1] = 0
> Liv1.HoleSize[2] = 22 Liv1.HoleX[2] = 900 Liv1.HoleY[2] = -55
must then result in :
> Liv1.HoleSize[0] = 14 Liv1.HoleX[0] = 750 Liv1.HoleY[0] = 0
> Liv1.HoleSize[1] = 22 Liv1.HoleX[1] = 250 Liv1.HoleY[1] = -55
> Liv1.HoleSize[2] = 22 Liv1.HoleX[2] = 900 Liv1.HoleY[2] = -55
As VBScript has no native sort, you'll have to roll your own sort, or to get a little help from friends.
If your task is to sort your input file (verbatim as given) to an output file in the specified order, sort.exe is your friend:
Dim sIn : sIn = "..\data\in00.txt"
WScript.Echo readAllFromFile(sIn)
WScript.Echo "-----------"
Dim sCmd : sCmd = "sort /+19 " & qq(resolvePath(sIn))
Dim aRet : aRet = goWSLib.Run(sCmd)
If aRet(0) Then
' handle error
Else
WScript.Echo aRet(2)
End If
output:
================================================================
Liv1.HoleSize[0] = 22 Liv1.HoleX[0] = 250 Liv1.HoleY[0] = -55
Liv1.HoleSize[1] = 14 Liv1.HoleX[1] = 750 Liv1.HoleY[1] = 0
Liv1.HoleSize[2] = 22 Liv1.HoleX[2] = 900 Liv1.HoleY[2] = -55
-----------
Liv1.HoleSize[1] = 14 Liv1.HoleX[1] = 750 Liv1.HoleY[1] = 0
Liv1.HoleSize[0] = 22 Liv1.HoleX[0] = 250 Liv1.HoleY[0] = -55
Liv1.HoleSize[2] = 22 Liv1.HoleX[2] = 900 Liv1.HoleY[2] = -55
================================================================
If something like that solves your problem, just say so, and we can talk the support code in the library functions.
If, however, you have (to) parse(d) the input file into a two-dimensional array, the best friend you can get is a disconnectes ADODB recordset:
Dim aData : aData = Split(Join(Array( _
"22 250 -55" _
, "14 750 0" _
, "22 900 -55" _
, "11 222 333" _
)))
Dim afData(3, 2)
Dim nRows : nRows = UBound(afData, 1)
Dim nCols : nCols = UBound(afData, 2)
Dim i, r, c
For i = 0 TO UBound(aData)
r = i \ nRows
c = i Mod (nCols + 1)
afData(r, c) = aData(i)
' WScript.Echo i, r, c, aData(i)
Next
For r = 0 To nRows
For c = 0 To nCols
WScript.StdOut.Write vbTab & afData(r, c)
Next
WScript.Echo
Next
WScript.Echo "-----------------"
Dim oRS : Set oRS = CreateObject("ADODB.Recordset")
For c = 0 To nCols
oRS.Fields.Append "Fld" & c, adInteger
Next
oRS.Open
For r = 0 To nRows
oRS.AddNew
For c = 0 To nCols
oRS.Fields(c).value = afData(r, c)
Next
oRS.UpDate
Next
oRS.Sort = "Fld0"
WScript.Echo oRS.GetString(adClipString, , vbTab, vbCrLf)
WScript.Echo "-----------------"
oRS.Sort = "Fld2"
WScript.Echo oRS.GetString(adClipString, , vbTab, vbCrLf)
output:
========================================
22 250 -55
14 750 0
22 900 -55
11 222 333
-----------------
11 222 333
14 750 0
22 250 -55
22 900 -55
-----------------
22 250 -55
22 900 -55
14 750 0
11 222 333
========================================
Again: if that looks promising, we can discuss how to adapt/streamline this proof of concept code to your needs.

Resources