VBA: Macro to loop through rows and Autofill - excel

EDIT: If I instead wanted to autofill these cells, would the following code work?
Sub BC_Edit()
' Define width and height of table
Dim datasetWidth, datasetHeight As Integer
' Find values for width and height of table
datasetWidth = Range("A1").End(xlToRight).Column
datasetHeight = Range("A1").End(xlDown).Row
' Loop over each column
For x = 1 To datasetWidth
Set sourceRange = Cells(2,x)
Set fillRange = Range(Cells(3, x), Cells(datasetHeight, x))
sourceRange.AutoFill Destination:=fillRange
Next
End Sub
I'm working with a couple of extremely large datasets - each approximately 3000 rows by 4000 columns. While Excel may not be the best tool for the job, I have already built a significant amount of infrastructure around the data and cannot move to a different framework. I'm using Excel 2007.
In a particular worksheet, when I try to Autofill using a formula I have inputted for the entire second column B (3000 x 1) via copy and paste of this column into the remaining 3000 by 3998 selection, or some part of this selection, Excel gives me a memory/resources error. So I would like to instead loop through each row and Autofill across all the columns. (In other words, I'd like to use A2 to autofill A3:A4000, B2 to autofill B3:B4000, and so on.) Perhaps this would help with the memory issue. How would I go about writing a macro to accomplish this?
I'd appreciate any advice on this issue, and perhaps some help with the appropriate VBA code, if possible.

Here is a pretty basic example of a macro to set columns below 2 to the formula of column 2.
It would be best to have this attached to a button or something similar rather than running every time you open the sheet.
Sub Button_Click()
' Define width and height of table
Dim datasetWidth, datasetHeight As Integer
' Find values for width and height of table
datasetWidth = Range("A1").End(xlToRight).Column
datasetHeight = Range("A1").End(xlDown).Row
' Loop over each column
For x = 1 To datasetWidth
' From row 3 to the height of data, set the formula of the cells to
' the formula contained in row 2 of that column
Range(Cells(3, x), Cells(datasetHeight, x)).Formula = Cells(2, x).Formula
Next
End Sub

Related

How to conditionally format a row in Excel VBA based on if first cell is empty?

What I'm trying to do is very simple, I just don't have much VBA / Excel experience to know how to do it.
I am working on a macro to do a few different things, I'm just stuck on this part.
What I want to do is go through all of my rows, and if the first cell in the row is empty, I want to select the entire row and UnMerge it. I know that if the first cell is empty, that row contains merged cells that I want unmerged.
I know that these two lines below will select row 2 and Unmerge it, but I need a way to loop through my data and find and unmerge the rows automatically, because the row numbers wont be the same every time.
Rows("2:2").Select
Selection.UnMerge
I want to do something like this:
For (each row) {
if (the first cell is empty) {
UnMerge all cells in that row;
}
}
I just don't know how to do that in VBA syntax.
Any help is appreciated!
This should do the job.
Sub UnmergeRows()
Dim R As Long ' loop counter: rows
With Worksheets("Sheet1") ' change tab name as required
' "B" should be the longest column in the worksheet
For R = 2 To .Cells(.Rows.Count, "B").End(xlUp).Row
If IsEmpty(.Cells(R, 1)) Then .Rows(R).MergeCells = False
Next R
End With
End Sub

Setting a dynamic print area

I am trying to define the print area for the active sheet that would include all rows in columns A thru X.
The number of rows changes with each active sheet.
This gives me a runtime error and thinks I'm trying to write a formula.
Sub setprintarea()
' Sets Range from cell A1 for all rows thru column 24 (X)
ActiveSheet.PageSetup.PrintArea = "$A$1:$X$"
End Sub
You have a minor syntax error. To specify full columns, you will want to specify "$A:$X". This may give the impression that you will print the entirety of columns A through X. However, that is not the case. Excel will print only enough sheets as needed for cells containing content.
As an example, create a new worksheet. On the worksheet, enter values in random cells in columns A through C. Next, set the print area to $A:$B. Now, do a print preview. You will see that Excel is smart enough to only create pages where data exists.
Corrected code:
ActiveSheet.PageSetup.PrintArea = "$A:$X"
It is true that the OP probably doesn't want the range to extend to the last row on the sheet. It is also possible that X is not the longest column on the sheet, in which case you would want to test each column to determine the sheet length. Hope this doesn't overcomplicate the matter, but sometimes the last column isn't the sheet length.
MaxLastRow = 1
For x = 1 To 24
If ActiveSheet.Cells(Rows.Count, x).End(xlUp).Row > MaxLastRow Then
MaxLastRow = ActiveSheet.Cells(Rows.Count, x).End(xlUp).Row
End If
Next x
ActiveSheet.PageSetup.PrintArea = "$A$1:$X$" & MaxLastRow
Dynamic Print Area
Sub setPrintArea()
With ActiveSheet
.PageSetup.PrintArea = Intersect(.UsedRange, .Columns("A:X")).Address
' Write the address to the Immediate window (CTRL+G).
Debug.Print .PageSetup.PrintArea
End With
End Sub

How can I calculate the sum of the numbers of two columns for only a portion of the rows?

Say I have an Excel sheet with 10,000 rows and two columns. All 20,000 cells are filled with numbers and there is no missing data. I want to have a third column, the values of which are the sum of Column A and Column B. For example, C70 = A70 + B70, and C82 = A82 + 82, and the like.
The only problem is I want to do it for only a portion of the rows, say from row 125 to row 8954. I don't care about the rest of the values. And I don't want to do it by dragging the grid using the mouse. Is that possible?
If you have access to SEQUENCE() (Currently only available to Office 365 Insiders) then yes it is possible:
=INDEX(A:A,SEQUENCE(1000,,ROW(),1))+INDEX(B:B,SEQUENCE(1000,,ROW(),1))
Where 1000 is the number of rows desired. Place the formula in the first cell desired and it will automatically fill the rest.
I believe you need some logic about what is going on, related to the start and end row.
You can use an if-statement or sumifs() for this... will do an if-statement so i can specify not meeting the requirements as null.
With Start row as 2 and end row as 4 (see image), you can use this formula, and drag it down to the bottom of all columns:
=IF(AND(ROW(A2)<=F$2,ROW(A2)>=E$2),SUM(A2:B2),"")
Notice in the image that C5 has no value; this is due to the conditions of the if-statement being false.
Another idea, a simple macro that will do what you want by asking the user what the starting and end row is.
Sub test()
Dim startrow As Integer 'variable to hold first row
Dim endrow As Integer 'variable to hold last row
startrow = InputBox("Enter the start row")
endrow = InputBox("Enter the end row")
'loops through you desired range calculating what you want
Dim i As Integer
For i = startrow To endrow
Cells(i, 4).Value = Cells(i, 1).Value + Cells(i, 2).Value
Next
End Sub
Just change the values to suit your needs in what cells you want to add up and where you want the sum to go.

Setting a dynamic range to Fill Down

I'm very new to using VBA with my excel workbooks.
I came across the following piece of code that #Manhattan provided as an answer to another question. It suits the needs of my workbook perfectly, but I need help with setting up a dynamic range.
What I am struggling to do now, is make the code only fill down enough rows to match up with the rows in column P (Which is the Row Labels column of the pivot table which the code below is pulling data from), except for the very last row (which is always "Grand Totals")?
Sub FillDown()
Dim strFormulas(1 To 3) As Variant
With ThisWorkbook.ActiveSheet
strFormulas(1) = "=SUM($Q3:$S3)"
strFormulas(2) = "=iferror(index(q3:s3,match($AE$2,$Q$2:$S$2,0)),0)"
strFormulas(3) = "=$AD3-$AE3"
.Range("AD3:AF3").Formula = strFormulas
.Range("AD3:AF150").FillDown
End With
End Sub
TL;DR: How can I make this code only fill down enough rows to match the last row -1 in column P?
Dynamically find the last row of column P (LR):
Dim LR as Long
LR = .Cells( .Rows.Count, "P").End(xlUp).Row
Then apply the last row minus 1 to your filldown:
.Range("AD3:AF" & LR-1).FillDown

How to retrieve value from a list and update in a matrix using excel

I developed a vegetation model in excel and need to add a grazing function.
I have several matrix which do all the calculations for the vegetation components, and now I have a list of steps (random cells visited, 750 out of 2500) and how much biomass was taken from that specific cell.
I need to update each cell value from that list into matrix format again, to calculate the remaining biomass. I've tried several combinations of "index" and "match" and lookups, but could not make it work.
I even numbered all 2500 cells for making it more simple, instead of using row and column reference. Any clue?? (would be the oposit of retrieving a value from a matrix using function Index)
I have something that I think will work for you. I created 3 worksheets. They are named VegMatrix, VisitedCells, and VegMatrixNew.
VegMatrix is the starting matrix and I assumed it was a 50 x 50 with the first data cell in A1. Here is a partial picture:
The next sheet is CellsVisited. It has the rows, cols and the amout of vegetation removed from the cell.
The third sheet is named VegMatrixNew. This is what the original matrix will look like after the removal occurs.
This is done using these VBA macros: They will copy the starting VegMatrix data over to the VegMatrixNew sheet. Then it will loop through the rows in the CellsVisited sheet and get the row, column and amount removed for each cell. The amount removed is subtracted from corresponding cell in VegMatrixNew.
Sub VegRemove()
Dim Wbk As Workbook
Set Wbk = ActiveWorkbook
Dim row As Integer
Dim col As Integer
Dim vegRemoved As Integer
Dim numRows As Integer
CopySheet
Worksheets("VisitedCells").Activate
numRows = Wbk.Worksheets("VisitedCells").Range("A2", Range("A2").End(xlDown)).Rows.Count
For x = 2 To numRows + 1 'start at 2 because of header.
row = Worksheets("VisitedCells").Cells(x, 1).Value
col = Worksheets("VisitedCells").Cells(x, 2).Value
vegRemoved = Worksheets("VisitedCells").Cells(x, 3).Value
Worksheets("VegMatrixNew").Cells(row, col).Value = Worksheets("VegMatrix").Cells(row, col).Value - vegRemoved
Next x
End Sub
Sub CopySheet()
Sheets("VegMatrix").Select
Cells.Select
Selection.Copy
Sheets("VegMatrixNew").Select
Range("A1").Select
ActiveSheet.Paste
Application.CutCopyMode = False
Range("A1").Select
End Sub
I just found a little easier way to do that:
I built a matrix with cell references (which correspond to the original vegetation matrix)
Harvested and corresponding reference table
Then I randomly generated the amount harvested from each cell. The "Reference" uses "index" function to search for the values of X (row) and Y (column) and gives the "cell name" for those specific coordinates.
Reference matrix
On another matrix, I have a if.error function followed by a value lookup
=IFERROR(VLOOKUP("Reference matrix","Reference --> Amount harvested",2,FALSE),0)
Now I can use this lates table to subtract from the original vegetation matrix.
(sorry I could not make this more clear but SO is keeping me from embeding tables and from posting more than two picture links).
Here is the last table that I could not post before:
Updated harvested matrix
The "IFERROR" places "0" where there is no information from the harvested list (cells not harvested)

Resources