Split a array in VBA and output to multiple columns in Excel - arrays

I have a long array that exceeds the maximum number of rows of a single column (1048576), and I wish to output this array into multiple columns, for example, if my array length is 3145728, and so I intend to create 3 separate arrays, each with length 1048576, so 1 to 1048576 would be output to column A, 1048577 to 2097152 to column B, and 2097153 to 3145728 to column C. My code attempted is as follows:
Sub test()
'for simplicity, just created a simply long array
Dim arrIn(1 To 3145728, 1 To 1) As Long
For i = 1 To 3145728
arrIn(i, 1) = i
Next i
'created 3 separate arrays, each with length of 1048576
Dim arrOut1(1 To 1048576, 1 To 1) As Long, arrOut2(1 To 1048576, 1 To 1) As Long, arrOut3(1 To 1048576, 1 To 1) As Long
Dim p As Long, p2 As Long, p3 As Long
'because counter p is going to be from 1 to 3145728, for the second and third arrays, the counter need to restart from 1 and upto 1048576
p2 = 1
p3 = 1
For p = 1 To 3145728
Select Case p
Case Is <= 1048576
arrOut1(p, 1) = arrIn(p, 1)
Case Is <= 2097152
arrOut2(p2, 1) = arrIn(p, 1)
p2 = p2 + 1
Case Is <= 3145728
arrOut3(p3, 1) = arrIn(p, 1)
p3 = p3 + 1
End Select
Next p
Range("A1:A1048576") = arrOut1
Range("B1048577: B2097152") = arrOut2
Range("C2097153:C3145728") = arrOut3
End Sub
The first column (arrOut1) was output to column A, however, when it comes to the second column (arrOut2), VBA returns Run-time error '1004': Menthod 'Range' of object '_Global' failed.
I checked the locals windows results, p2 and p3 were 1048577, and arrOut2(1,1) = 1048577, arrOut2(1,1) = 1048578, and so on, seems the arrays all get populated, however I'm not sure what is prohibiting them from being spitted out to the columns. Thank you for your advice.

Ok so, just realized that Range(“B1048577:B...) was nonsense... so it is solved. Thank you!

Related

How to do SUM on array from outside file?

I'm newbie college student for programming studies,
so recently i have task to calculate matrix from outside files for Gauss Jordan Numeric Method, in the txt file i provide has 10 (x) and (y) data, and declare with do functions to calculate the 10 data from the txt file each for x^2, x^3, x^4, xy, x^2y
my question is : how to SUM (calculate total) each x^2, x^3 ... that was calculated by program ? i try do sum file in below and still got errors (the first argument of sum must not a scalar.)
the Fortran apps i use was Plato cc from Silverfrost.
I apologize if my english bad and my pogram looks funny.
i have 10 data in my txt looks like these :
(x) (y)
12 10
5 6
28 8
9 11
20 17
6 24
32 9
2 7
1 30
26 22
in program below i open these files and want each x and y i provide read and calculate to get x^2, x^3, x^4, xy, x^2y
Program Gauss_Jordan
Real x(10),y(10),xj,yj,xj2,xj3,xj4,xjyj,xj2yj
Open (10, file='Data.txt')
Do j = 1,10
Read(10,*) x(j), y(j)
xj2 = x(j)**2
xj3 = x(j)**3
xj4 = x(j)**4
xjyj = x(j)*y(j)
xj2yj = (x(j)**2)*y(j)
Do k = 1,10
T(xj2) = SUM( xj2, dim=1)
T(xj3) = SUM (xj3, dim=1)
T(xj4) = SUM (xj4, dim=1)
T(xjyj) = SUM (xjyj, dim=1)
T(xj2yj) = SUM (xj2yj, dim=1)
End Do
End Do
Close(10)
End
for T(xj2) I want to get one result scalar result from SUM the all xj^2 that program has been calculated.
Like in excel was expected :
(A) is 1st xj^2 value that has been calculated
.
.
.
until (J) is 10th xj^2 value that has been calculated
sxj^2 = SUM(Xj^2)
SUM (A-J)
The 'sum' intrinsic needs an array argument, which we can compute from the input arrays without using a loop, so your program could be:
Program Gauss_Jordan
Real x(10), y(10), x2(10), x3(10), x4(10), xy(10), x2y(10)
Open(10, file='Data.txt')
Do j = 1, 10
Read (10, *) x(j), y(j)
End Do
Close(10)
x2 = x**2
x3 = x**3
x4 = x**4
xy = x*y
x2y = (x**2)*y
sx2 = SUM(x2)
sx3 = SUM(x3)
sx4 = SUM(x4)
sxy = SUM(xy)
sx2y = SUM(x2y)
End
From what I see I think you are misunderstanding what the SUM intrinsic does. Since your example isn't storing xj2, xj3 etc. in arrays, SUM isn't going to be useful to you. Instead you could declare totals as scalars (as you described you wanted) and simply add the individual xj2 variables in a loop as in the example below.
Also, you should get in the habit of using the implicit none declaration. It will save you from unexpected errors due to spelling mistakes.
Program Gauss_Jordan
implicit none
Real x(10),y(10),xj,yj,xj2,xj3,xj4,xjyj,xj2yj
real :: Txj2,Txj3,Txj4,Txjyj,Txj2yj
integer :: j
Txj2 = 0
Txj3 = 0
Txj4 = 0
Txjyj= 0
Txj2yj= 0
Open (10, file='Data.txt')
Do j = 1,10
Read(10,*) x(j), y(j)
xj2 = x(j)**2
xj3 = x(j)**3
xj4 = x(j)**4
xjyj = x(j)*y(j)
xj2yj = (x(j)**2)*y(j)
Txj2 = Txj2 + xj2
Txj3 = Txj3 + xj3
Txj4 = Txj4 + xj4
Txjyj = Txjyj + xjyj
Txj2yj = Txj2yj + xj2yj
End Do
print *, 'Txj2 = ', Txj2
Close(10)
End
When I ran this I got the output below which is what I believe you intended:
3175

Excel VBA code needed to copy row if criteria is met

I have an excel document with two sheets. Sheet 1 has columns A-Q and Sheet 2 has columns A-H. What I need is a code that will copy the information in a row from sheet 1 to sheet 2 if the criteria is met. The criteria is the word "Awarded" in column L (Sheet 1).
Also is it possible to have only specific columns in the row copied?
A B C D E F G H I J K L M N
X X Awarded X X
I would like to have only columns C,D,M, and N copied from the row if the word "awarded" is in column L. This information would be copied to Sheet 2 in the following fashion
Sheet 1 Sheet 2
D --> B
C --> C
M --> D
N --> F
I hope I'm being clear. Thanks in advance and let me know if I need to clarify!+
This is the code I currently have, which works. Only problem is it copies the entire row of information into sheet 2 when I only want rows D,C,M, and N to be copied.
Sub testing()
Set a = Sheets("Sheet1")
Set b = Sheets("Sheet2")
Dim d
Dim j
d = 1
j = 2
Do Until IsEmpty(a.Range("L" & j))
If a.Range("L" & j) = "Awarded" Then
d = d + 1
b.Rows(d).Value = a.Rows(j).Value
End If
j = j + 1
Loop
End Sub
First what you should do is change your data structure. Assuming you are using Excel 2007 or later, there is a great feature called Tables. If you highlight all of your data and go to Insert->Table, select the "My Table Has Headers" checkbox, and press ok, you will see a nicely formatted table. Do that for both of the data sets on each sheet.
This is more than just pretty formatting though, it is what is called a ListObject. In your VBA code, use the following to reference it:
Dim Table1 as ListObject, Table 2 as ListObject
Dim HeaderIndex as Integer
Dim MyColumnRange as Range
Set Table1 = Sheet1.ListObjects("TableName1")
`Change the table name under Formulas->Name Manager
Set Table2 = Sheet1.ListObjects("TableName2")
HeaderIndex = Application.WorksheetFunction.Match("ColumnLHeaderName", _
Table1.HeaderRowRange, 0)
Set MyColumnRange = Table1.ListColumns(HeaderIndex).DataBodyRange
MyColumnRange.Select
At this point, the select statement is just to show you what range you are dealing with now. The HeaderIndex refers to the header sub component of the table ListObject. Using Match() will allow you to specify the name of the column header without hard coding it's position. (i.e. if your data starts in column A, the header value in column L will return HeaderIndex = 12)
Now that you know what column you want, you select the ListColumn object. Then, the DataBodyRange is used to select the range component of that object. This is the entire range in that column. You can then iterate down the list to find the data you want.
EDIT: Updated Example:
'Specify your ranges you will be copying from beforehand, adding as many as you need here.
HeaderIndex_D = Application.WorksheetFunction.Match("ColumnXHeaderName", _
Table1.HeaderRowRange, 0)
HeaderIndex_C = Application.WorksheetFunction.Match("ColumnXHeaderName", _
Table1.HeaderRowRange, 0)
HeaderIndex_M = Application.WorksheetFunction.Match("ColumnXHeaderName", _
Table1.HeaderRowRange, 0)
HeaderIndex_N = Application.WorksheetFunction.Match("ColumnXHeaderName", _
Table1.HeaderRowRange, 0)
Set ColumnRange_D= Table1.ListColumns(HeaderIndex_D).DataBodyRange
Set ColumnRange_C= Table1.ListColumns(HeaderIndex_C).DataBodyRange
Set ColumnRange_M= Table1.ListColumns(HeaderIndex_M).DataBodyRange
Set ColumnRange_N= Table1.ListColumns(HeaderIndex_N).DataBodyRange
'Now, loop through each row that exists in your table. If the testing
'condition contained in MyColumnRange you previously defined is met,
'then assign the destination cell (which can be defined in the same way
'as above) equal to the lookup range's current row value (specified by i)
For i = 1 to MyColumnRange.Rows.Count
If MyColumnRange(i) = "Awarded" Then
DestinationCell1.Value = ColumnRange_D(i)
DestinationCell2.Value = ColumnRange_C(i)
DestinationCell3.Value = ColumnRange_M(i)
DestinationCell4.Value = ColumnRange_N(i)
End If
Next i

VBA Error Handling Multiple times

I have an issue. I have values in a workbook that are getting read into an array. The values come from an XML list so sometimes can be numbers or text, and if they are numbers in text format ("1" for example), they need to be converted to number format, so I multiply them by 1. If the value is text "LS" for example, I am trying to use an error handler to keep the value as "LS".
I have developed the code below: It works once, but the next time I use a similar method (with 'Dummy2') the code it produces a 'Type Mismatch' error.
On Error GoTo Dummy1
For i = 1 To nrows1 - 1
If (Worksheets("Import").Cells(i + 1, 26) * 1 = "") Then
Dummy1:
Table1(i, 1) = Worksheets("Import").Cells(i + 1, 26)
Else
Table1(i, 1) = Worksheets("Import").Cells(i + 1, 26) * 1
End If
Next
On Error GoTo 0
I also tried Clearing Err after the above code with no success.
Please help!
You can use the IsNumeric function:
Sub test3()
Dim Test As Variant
Dim i As Long
For i = 1 To nrows1 - 1
Test = Worksheets("Import").Cells(i + 1, 26)
If IsNumeric(Test) Then
Table1(i, 1) = Test * 1
Else
Table1(i, 1) = Test
End If
Next
End Sub
use VAL(Worksheets("Import").Cells(i + 1, 26)) to determine if it is a Number or not. VAL will give you 0 for "LS".
You could try TryParse functions - but not sure if its available in your version of VBA

How do I make this specific code run faster in Matlab?

I have an array with a set of chronological serial numbers and another source array with random serial numbers associated with a numeric value. The code creates a new cell array in MATLAB with the perfectly chronological serial numbers in one column and in the next column it inserts the associated numeric value if the serial numbers match in both original source arrays. If they don't the code simply copies the previous associated value until there is a new match.
j = 1;
A = {random{1:end,1}};
B = cell2mat(A);
value = random{1,2};
data = cell(length(serial), 1);
data(:,1) = serial(:,1);
h = waitbar(0,'Please Wait...');
steps = length(serial);
for k = 1:length(serial)
[row1, col1, vec1] = find(B == serial{k,1});
tf1 = isempty(vec1);
if (tf1 == 0)
prices = random{col1,2};
data(j,2) = num2cell(value);
j = j + 1;
else
data(j,2) = num2cell(value);
j = j + 1;
end
waitbar(k/steps,h,['Please Wait... ' num2str(k/steps*100) ' %'])
end
close(h);
Right now, the run-time for the code is approximately 4 hours. I would like to make this code run faster. Please suggest any methods to do so.
UPDATE
source input (serial)
1
2
3
4
5
6
7
source input (random)
1 100
2 105
4 106
7 107
desired output (data)
SR No Value
1 100
2 105
3 105
4 106
5 106
6 106
7 107
Firstly, run the MATLAB profiler (see 'doc profile') and see where the bulk of the execution time is occuring.
Secondly, don't update the waitbar on every iteration> Particularly if serial contains a large (> 100) number of elements.
Do something like:
if (mod(k, 100)==0) % update on every 100th iteration
waitbar(k/steps,h,['Please Wait... ' num2str(k/steps*100) ' %'])
end
Some points:
Firstly it would help a lot if you gave us some sample input and output data.
Why do you initialize data as one column and then fill it's second in the loop? Rather initialize it as 2 columns upfront: data = cell(length(serial), 2);
Is j ever different from k, they look identical to me and you could just drop both the j = j + 1 lines.
tf1 = isempty(vec1); if (tf1 == 0)... is the same as the single line: if (!isempty(vec1)) or even better if(isempty(vec1)) and then swap the code from your else and your if.
But I think you can probably find a fast vecotrized solution if you provide some (short) sample input and output data.

Find average of a specific number of rows/columns in VB.Net Datatable and store to array

I am trying to program a noise reduction algorithm that works with a set of datapoints in a VB.NET DataTable after being helped with my other question. Basically, I want to take two integers, a coordinate value (yCoord for example) and a threshold smoothing value (NoiseThresh), and take the average of the values in the range of (yCoord - NoiseThresh, yCoord + NoiseThresh) and store that number into an array. I'd repeat that process for each column (in this example) and end up with a one-dimensional array of average values. My questions are:
1) Did anything I just say make any sense ;), and
2) Can anyone help me with the code? I've got very little experience working with databases.
Thanks!
An example of what I'm trying to do:
//My data (pretend it's a database)
1 4 4 9 2 //yCoord would equal 5
6 3 8 12 3 //yCoord = 4
8 3 -2 2 0 //yCoord = 3
9 17 3 7 5 //yCoord = 2
4 1 0 9 7 //yCoord = 1
//In this example, my yCoord will equal 3 and NoiseThresh = 1
//For the first column
Array(column1) = //average of the set of numbers centered at yCoord = 3 _
//(in this case 8) and the NoiseThresh=1 number on either side (here 6 & 9)
//For the second column
Array(column2) = //average of the numbers 3,3,17 for example
//etc., etc.,
This would be performed on a large data set (typical numbers would be yCoord=500, NoiseThresh = 50, Array length = 1092) so there is no possibility of manually entering the numbers.
I hope this helps clarify my question!
P.S.: yes, I know that // isn't a VB.NET comment.
I must admit that i've yet not understood the range part (NoiseThresh etc.), but this is a start:
Dim averages = (From col In tbl.Columns.Cast(Of DataColumn)()
Select tbl.AsEnumerable().
Average(Function(r) r.Field(Of Int32)(col.ColumnName))).
ToArray()
It calculates every average of each column in the DataTable and creates a Double() from the result (average can result in decimal places even if used on integers).
Edit: With your example i've now understood the range part. So basically yCord is the row-index(+1) and noiseThreas is the row-range (+/- n rows).
Then this gives you the correct result(made some code comments):
Dim yCord = 2 ' the row index(-1 since indices are 0-based) '
Dim noiseThresh = 1 ' +/- row '
' reverse all rows since your sample begins with index=5 and ends with index=1 '
Dim AVGs As Double() = (
From colIndex In Enumerable.Range(0, tbl.Columns.Count)
Select tbl.AsEnumerable().Reverse().
Where(Function(r, index) index >= yCord - noiseThresh _
AndAlso index <= yCord + noiseThresh).
Average(Function(r) r.Field(Of Int32)(colIndex))).ToArray()
The most important part of this this LINQ query is the Where. It applies your range on the IEnumerable(of DataRow). Then i'm calculating the average of these rows for every column. The last step is materializing the query to a Double().
Result:
(0) 7.666666666666667 Double => (6+8+9)/3
(1) 7.666666666666667 Double => (3+3+17)/3
(2) 3.0 Double => (8-2+3)/3
(3) 7.0 Double => (12+2+7)/3
(4) 2.6666666666666665 Double => (3+0+5)/3
Edit2:
One last thing. I assume that to do the same for the other axis I just
switch x & y and row & column?
It's not that simple. But have a look yourself:
Dim noiseThresh = 1 ' +/- column '
Dim xCord = 2 ' the column index(-1 since indices are 0-based) '
' assuming that your x-cords now start with index=0 and ends with tbl.Column.Count-1 '
Dim AVGs As Double() = (
From rowIndex In Enumerable.Range(0, tbl.Rows.Count)
Select tbl.Columns.Cast(Of DataColumn)().
Where(Function(c, colIndex) colIndex >= xCord - noiseThresh _
AndAlso colIndex <= xCord + noiseThresh).
Average(Function(c) tbl.Rows(rowIndex).Field(Of Int32)(c.Ordinal))).ToArray()
Result:
(0) 5.666666666666667 Double => (4+4+9)/3
(1) 7.666666666666667 Double => (3+8+12)/3
(2) 1.0 Double => (3-2+2)/3
(3) 9.0 Double => (17+3+7)/3
(4) 3.3333333333333335 Double => (1+0+9)/3

Resources