working with arrays - vb.net

I am working with Visual Basic and i need to Find the total of each column in the last row
Find the grand total in the last cell(the bottom right corner). I know how to do the total thing for this class. But this subject I am working with Arrays. I am sure if that will work with the arrays or will it. I need to have a total at the bottom for this. I am not to sure on how to do it. So if maybe someone might have website i can read on about or something I would be happy. Thanks.
Again this is what I am suppose to do:Find the total of each column in the last row
Find the grand total in the last cell(the bottom right corner).
Module Module1
Sub Main()
Dim sum(5, 4) As Integer
Dim row, col As Integer
Dim total As Integer
For row = 0 To 4
For col = 0 To 3
sum(row, col) = row + col
sum(row, 4) += row + col
Next col
Next row
For row = 0 To 5
For col = 0 To 4
Console.Write(sum(row, col) & vbTab)
Next col
Console.WriteLine()
Next row
End Sub
End Module

One big problem is that you're traversing the array by ROWS then columns.
Doing that, you'll sum up each ROW not each COLUMN.
First step would be to reverse that.
Second, you appear to be storing the col totals on row 4, so you can't step down to row 4, just row 3.
Finally, you appear to be adding the value of the row and col vars, instead of the array entry pointed to by those vars.
Something more like this
For col = 0 to 3
for row = 0 to 3
sum(4, 4) += Sum(row, col)
sum(4, col) += Sum(row, col)
...

Related

How to sum up rows in excel using VBA

I'm creating my first module, using VBA, and not sure how to sum up rows. I was wondering if someone could help me. I have a file of transactions, picture attached:
I'm trying to insert a break (blank row) in between date groups (group all transaction from a specific date), and then a sum of each total in the break under each column for the corresponding date. My code is as follows, but I'm stuck on how to create the sum as I'm not sure the syntax. Here is the code I came up with:
Sub InsertRowsBetweenDates()
'
' InsertRowsBetweenDates Macro
' Insert Rows in between two dates that are not equal
'
Dim x As Integer
Dim y As Integer
Dim row1 As Range
Dim row2 As Range
Dim t As Integer 'tracking how many cells to add together
'define x as cell row value
x = 2
'define y as cell row value
y = 3
'start tracker at 0
t = 0
'row 1 and row 2 get their values
Set row1 = Cells(x, 4)
Set row2 = Cells(y, 4)
'Do until there are no more entries in the worksheet (or really until row 1 has no value)
Do Until row1.Value = False
x = x + 1
y = y + 1
Set row1 = Cells(x, 4)
Set row2 = Cells(y, 4)
t = t + 1
'If row 1 and 2 don't equal each other, insert a row above row 2
If row1 <> row2 Then
row2.EntireRow.Insert Shift:=xlDown
'sum up t rows for subtotal and tax [THIS IS WHAT IM STUCK ON]
'skip the break
x = x + 2
y = y + 2
Set row1 = Cells(x, 4)
Set row2 = Cells(y, 4)
t = 0
End If
Loop
End Sub
As you can see, I got the break to work, albeit it only works for this file as the rows and column positions are hardcoded, but its a start. At this point I have a tracker to track how many rows have been counted, and I think I just need to insert code to sum up the rows. How would I go about achieving this?
I think you're heading completely at the wrong path.
I wouldn't do that unless I totally and utterly HAVE TO
Why?
Because you're putting the data together with the report. What happens when someone need to insert a row? What happens when someone has to maintain your code?
Look at the following options:
1. Use the source as a table and summarize with a pivot table
2. Add a column and use the SUMIF function
These ways you avoid using VBA altogether and still manage to get the reports you need. Good luck!

Ranking a dynamic table range by size

I have a dynamic table range of certain values (amounts). These amounts are generated into the table through a macro I've created.
What I want to do: Rank these amounts into the empty column by number.
eg. the cell in Column G next to 89k would be ranked as 1, one next to 77k would be 2 etc.
I also already have other functions defined, which I'm not going to explain here for readability reasons, but all you need to know: there are two variables obtained through functions
tbl_first = (int) Index of the ListRow of the first table item (so in this case it would be the row with 89k = 1st row so in this example 1)
tbl_last = (int) same as above, but indexes the last row (77k) in this example as 7
so my code is the following
' sets the tbl variable to the red table in the picture
Dim tbl As ListObject: Set tbl = Sheets("Summary").ListObjects("time_top")
Dim pos As Integer, diff as integer
diff = tbl_last - tbl_first
For j = tbl_first To tbl_last ' loops through all the added rows
For n = 1 to diff' indexing for the large function
' index the pos through the excel large function for our values (should return the k-th position from the largest value)
pos = Application.WorksheetFunction.Large(Range(Cells(tbl_first, 6), Cells(tbl_last, 6)), n)
With tbl.ListRows(1)
.Range(j, 6) = pos ' add the value to the column G to the right
End With
Next n
Next j
So the expected result would look like this:
I also keep getting the following error, which is caused by me incorrectly assigning the pos value.
Either way, probably multiple of things wrong here and much more elegant solution is out there, that just didn't hit me yet.
Think you need Rank (watch out for equal ranks). Large returns the nth largest value of a set.
Here is a simple example on a two column table which perhaps you can adapt. The rank is added in the second column.
Sub xx()
Dim tbl As ListObject: Set tbl = Sheets("Summary").ListObjects("time_top")
Dim r As Range
For Each r In tbl.ListColumns(1).DataBodyRange
r.Offset(, 1) = WorksheetFunction.Rank(r, tbl.ListColumns(1).DataBodyRange)
Next r
End Sub

Excel: Reference non-zero cells

I'm trying to list 50 rows x 8 columns of cells (defined 'allhazards') into one column
However each cell in myhazards is referencing other sheets and contain 0's where there is no text to be referenced.
When I list the data in 'allhazards' in a single column using this formula:
=INDEX(allhazards,1+INT((ROW($A1)-1)/COLUMNS(allhazards)),MOD(ROW($A1)-1+COLUMNS(allhazards),COLUMNS(allhazards))+1)
(then drag down the column to get all of the cells from 'allhazards')
How do I implement this:
if cell in 'allhazards' is 0, do not reference this cell, move to next row
...then reference next row's columns until cell is 0, then move to next row
...keep doing this until there are no rows left to be referenced
eg. if 'allhazards' contained these cells (eg. 2 rows x 8 columns):
hello how are 0 0 0 0 0
good 0 0 0 0 0 0 0
It should produce this when dragging down the formula:
hello
how
are
good
but not this:
hello
how
are
0
0
0
0
0
good
0
0
0
0
0
0
0
I created a UDF for your situation. Please place the following procedure in a standard code module.
Public Function MATRIX2VECTOR(r As Range)
Dim i&, j&, k&, v, m, o
v = r
ReDim o(1 To Application.Caller.Rows.Count, 1 To 1)
For i = 1 To UBound(v, 1)
For j = 1 To UBound(v, 2)
m = v(i, j)
If Len(m) Then
If m <> 0 Then
k = k + 1
o(k, 1) = v(i, j)
End If
End If
Next
Next
For k = k + 1 To UBound(o): o(k, 1) = "": Next
MATRIX2VECTOR = o
End Function
Now you can call it in a formula from the worksheet just like any of the built-in functions.
1
Select a vertical range of cells tall enough to accommodate the transposed data.
2
Click in the Formula Bar at the top of Excel.
3
Enter this formula:
=MATRIX2VECTOR(allhazards)
4
This is an array formula and must be confirmed with Ctrl+Shift+Enter.
If you're interested in a non-VBA solution:
=IF(ROWS($1:1)>COUNTIF(allhazards,"<>0"),"",INDIRECT(TEXT(AGGREGATE(15,6,(10^5*ROW(allhazards)+COLUMN(allhazards))/(allhazards<>0),ROWS($1:1)),"R0C00000"),0))
Copy down as required.
This will be more efficient if you use a single helper cell to store the number of non-zero entries in allhazards, and also store the ROW/COLUMN portion as a Defined Name. For example, if you put:
=COUNTIF(allhazards,"<>0")
in e.g. J1, and define, in Name Manager, Arry1 as:
=10^5*ROW(allhazards)+COLUMN(allhazards)
then the main formula becomes:
=IF(ROWS($1:1)>$J$1,"",INDIRECT(TEXT(AGGREGATE(15,6,Arry1/(allhazards<>0),ROWS($1:1)),"R0C00000"),0))
If your data is in a different sheet to that housing the results, simply include the sheet name containing the data, viz:
=IF(ROWS($1:1)>$J$1,"",INDIRECT("'YourSheetName'!"&TEXT(AGGREGATE(15,6,Arry1/(allhazards<>0),ROWS($1:1)),"R0C00000"),0))
Regards

Looping until blank column

I am putting together some VBA code which i think needs a loop. Loops are often my biggest weakness with VBA and I need some assistance.
I have a text file which i import into an excel spreadsheet. The length of how many columns and rows and down will vary day to day.
For example today's file might have data in columns A - H, tomorrow it might be A : P. Each typical row count will be around the 200 mark, so not to long.
In essence im trying to make one long list in column A from all the data spread over multiple columns.
Im looking for a loop that checks if the column has data in it, if it does it then copies the data into the bottom of the data in column A.
So for illustration purposes say the data goes out to column G, it will copy B1, xl down, find the first empty row in A and paste, then do the same for C, stopping after column G.
I hope I’ve been clear when writing this.
Thanks in advance
Matt
You first want to loop over all columns. So a FOR loop from column B to LastColumn (which there is a function for.) Then you want to loop through all rows within that column to find the first empty row, and then substract one to arrive at the last column with data.
If Cells(row,col) = "" Then
LastRowCopy = row -1
Then you want to copy everything to A1, and keep track of the last row you posted in. So you want to have a variable that counts. Something like:
LastRowPaste = LastRowPaste + row
I could write the code for it, but perhaps you learn more by figuring it out yourself.
Edit: Also perhaps an interesting read on finding last rows and or columns is this: http://www.rondebruin.nl/win/s9/win005.htm
Edit2: You could ofcourse also use the same for finding the last column as the method I used for finding the last row. Then you just loop through the columns and see if:
If Cells(1, col) = "" Then
LastCol = col -1
Edit3:
I wrote out the entire code:
Sub copypaste()
Dim LastRowCopy As String
Dim LastRowPaste As String
Dim LastCol As String
Dim col As Integer
Dim row As Integer
LastCol = ActiveSheet.UsedRange.Columns.Count
LastRowCopy = ActiveSheet.UsedRange.Rows.Count
LastRowPaste = ActiveSheet.UsedRange.Rows.Count
For row = 1 to LastRowPaste
If Cells(row, 1) = "" Then
LastRowPaste = row
Exit For
End if
Next row
For col = 2 To LastCol
If Application.WorksheetFunction.CountA(Columns(col)) = 0 Then
LastCol = col -1
End If
Next col
For col = 2 To LastCol
For row = 1 To LastRowCopy
If Not Cells(row, col) = "" Then
Cells(LastRowPaste, 1) = Cells(row, col)
LastRowPaste = LastRowPaste + 1
End If
Next row
Next col
End Sub

Colouring datagrid rows

I was wondering how to colour the first 8 rows of a datagridview. I have managed to sort the values in descending order and I wish to have the first 8 rows coloured to highlight the top 8 to the user, and I'm not sure how to go about doing this.
Dim count As Integer
For count = 0 To datagridsort.RowCount - 1
Do
datagridsort.Rows(0).Cells(0).Style.BackColor = Color.Coral
datagridsort.Rows(0).Cells(1).Style.BackColor = Color.Coral
Loop Until count = 8
Next
In the code you posted in your comment, you were never using the count variable. You were only updated the first row every time. Try it like this:
For i As Integer = 0 To Math.Min(datagridsort.RowCount - 1, 7)
For j As Integer = 0 To datagridsort.ColumnCount - 1
datagridsort.Rows(i).Cells(j).Style.BackColor = Color.Coral
Next
Next