I was wondering if it is possible for someone to help me shorten the code as i'm afraid it might take a long time to run after i add in other codes. What i want to do will be explain in the following:
I want to copy say test2 (do take note that the spacing means the variables are on their own row and column)
test1 1 2 1
test2 2 1 4
test3 1 1 1
After copying it I will paste it at some other sheet.
Let say, I have another set of results
Say
test2 2 1 4
test3 3 9 8
test5 1 1 1
I wanted to copy test2 but my VBA coding werent able to as it still assumes that test2 is at 2nd row.
And one last case would be, if test2 not available, it will continue on copying the rest of the result and paste it at other sheets.
I have did some coding, do run through and help me solve this problem. THANKS!
Sub Macro1()
iMaxRow = 6 ' or whatever the max is.
'Don't make too large because this will slow down your code.
' Loop through columns and rows
For iCol = 1 To 1 ' or however many columns you have
For iRow = 1 To 1
With Worksheets("Sheet3").Cells(iRow, iCol)
' Check that cell is not empty.
If .Value = "Bin1" Then
Range("A1:G1").Select
Selection.Copy
Sheets("sheet4").Select
Range("A1").Select
ActiveSheet.Paste
Sheets("sheet3").Select
ElseIf .Value = "Bin2" Then
Range("A1:G1").Select
Selection.Copy
Sheets("sheet4").Select
Range("A1").Select
ActiveSheet.Paste
Sheets("sheet3").Select
ElseIf .Value = "Bin3" Then
Range("A1:G1").Select
Selection.Copy
Sheets("sheet4").Select
Range("A1").Select
ActiveSheet.Paste
Sheets("sheet3").Select
ElseIf .Value = "Bin4" Then
Range("A1:G1").Select
Selection.Copy
Sheets("sheet4").Select
Range("A1").Select
ActiveSheet.Paste
Sheets("sheet3").Select
ElseIf .Value = "Bin5" Then
Range("A1:G1").Select
Selection.Copy
Sheets("sheet4").Select
Range("A1").Select
ActiveSheet.Paste
Sheets("sheet3").Select
ElseIf .Value = "Bin6" Then
Range("A1:G1").Select
Selection.Copy
Sheets("sheet4").Select
Range("A1").Select
ActiveSheet.Paste
Sheets("sheet3").Select
End If
End With
Next iRow
Next iCol
For iCol1 = 1 To 1 ' or however many columns you have
For iRow1 = 1 To 2
With Worksheets("Sheet3").Cells(iRow1, iCol1)
' Check that cell is not empty.
If .Value = "Bin2" Then
Range("A2:G2").Select
Selection.Copy
Sheets("sheet4").Select
Range("A2").Select
ActiveSheet.Paste
Sheets("sheet3").Select
ElseIf .Value = "Bin3" Then
Range("A2:G2").Select
Selection.Copy
Sheets("sheet4").Select
Range("A2").Select
ActiveSheet.Paste
Sheets("sheet3").Select
ElseIf .Value = "Bin4" Then
Range("A2:G2").Select
Selection.Copy
Sheets("sheet4").Select
Range("A2").Select
ActiveSheet.Paste
Sheets("sheet3").Select
ElseIf .Value = "Bin5" Then
Range("A2:G2").Select
Selection.Copy
Sheets("sheet4").Select
Range("A2").Select
ActiveSheet.Paste
Sheets("sheet3").Select
ElseIf .Value = "Bin6" Then
Range("A2:G2").Select
Selection.Copy
Sheets("sheet4").Select
Range("A2").Select
ActiveSheet.Paste
Sheets("sheet3").Select
End If
End With
Next iRow1
Next iCol1
For iCol2 = 1 To 1 ' or however many columns you have
For iRow2 = 1 To 3
With Worksheets("Sheet3").Cells(iRow2, iCol2)
' Check that cell is not empty.
If .Value = "Bin3" Then
Range("A3:G3").Select
Selection.Copy
Sheets("sheet4").Select
Range("A3").Select
ActiveSheet.Paste
Sheets("sheet3").Select
ElseIf .Value = "Bin4" Then
Range("A3:G3").Select
Selection.Copy
Sheets("sheet4").Select
Range("A3").Select
ActiveSheet.Paste
Sheets("sheet3").Select
ElseIf .Value = "Bin5" Then
Range("A3:G3").Select
Selection.Copy
Sheets("sheet4").Select
Range("A3").Select
ActiveSheet.Paste
Sheets("sheet3").Select
ElseIf .Value = "Bin6" Then
Range("A3:G3").Select
Selection.Copy
Sheets("sheet4").Select
Range("A3").Select
ActiveSheet.Paste
Sheets("sheet3").Select
End If
End With
Next iRow2
Next iCol2
For iCol3 = 1 To 1 ' or however many columns you have
For iRow3 = 1 To 4
With Worksheets("Sheet3").Cells(iRow3, iCol3)
' Check that cell is not empty.
If .Value = "Bin4" Then
Range("A4:G4").Select
Selection.Copy
Sheets("sheet4").Select
Range("A4").Select
ActiveSheet.Paste
Sheets("sheet3").Select
ElseIf .Value = "Bin5" Then
Range("A4:G4").Select
Selection.Copy
Sheets("sheet4").Select
Range("A4").Select
ActiveSheet.Paste
Sheets("sheet3").Select
ElseIf .Value = "Bin6" Then
Range("A4:G4").Select
Selection.Copy
Sheets("sheet4").Select
Range("A4").Select
ActiveSheet.Paste
Sheets("sheet3").Select
End If
End With
Next iRow3
Next iCol3
For iCol4 = 1 To 1 ' or however many columns you have
For iRow4 = 1 To 5
With Worksheets("Sheet3").Cells(iRow4, iCol4)
' Check that cell is not empty.
If .Value = "Bin5" Then
Range("A5:G5").Select
Selection.Copy
Sheets("sheet4").Select
Range("A5").Select
ActiveSheet.Paste
Sheets("sheet3").Select
ElseIf .Value = "Bin6" Then
Range("A5:G5").Select
Selection.Copy
Sheets("sheet4").Select
Range("A5").Select
ActiveSheet.Paste
Sheets("sheet3").Select
End If
End With
Next iRow4
Next iCol4
For iCol5 = 1 To 1 ' or however many columns you have
For iRow5 = 1 To 6
With Worksheets("Sheet3").Cells(iRow5, iCol5)
' Check that cell is not empty.
If .Value = "Bin6" Then
Range("A6:G6").Select
Selection.Copy
Sheets("sheet4").Select
Range("A6").Select
ActiveSheet.Paste
Sheets("sheet3").Select
End If
End With
Next iRow5
Next iCol5
Sheets("Sheet4").Select
Range("A1").Select
End Sub
I am struggling to identify what your code does. Below I specify some simplifications and other necessary improvements but there may be more once we have cleared the brushwood.
Change 1
Please use Option Explicit and please declare your variables. This avoids a misspelt variable being taken as a new implicit declaration.
Change 2
Please use Application.ScreenUpdating = False. This avoids repainting the screen as the macro works through its tasks. This would have been essential with your code because of all the switching between sheets. It is less important with my code because I do not switch sheets.
Change 3
Replace:
With Sheets("Sheet3")
:
Range("A1:G1").Select
Selection.Copy
Sheets("sheet4").Select
Range("A1").Select
ActiveSheet.Paste
Sheets("sheet3").Select
:
End With
by:
With Sheets("Sheet3")
:
.Range("A1:G1").Copy Destination:=Worksheets("Sheet4").Range("A1")
:
End With
This avoids switching sheets which is the biggest waste of time.
Change 4
For each If-ElseIf-ElseIf-EndIf you do the same copy. So:
If .Value = "Bin1" Or .Value = "Bin2" Or .Value = "Bin3" _
.Value = "Bin4" Or .Value = "Bin5" Then
would have the same effect.
Summary so far
I believe the following does exactly the same as your first loop:
Option Explicit
Sub Macro1()
Dim iCol As Long
Dim iRow As Long
Dim ValueCell as String
With Sheets("Sheet3")
For iCol = 1 To 1
For iRow = 1 To 1
ValueCell = .Cells(iRow, iCol).Value
If ValueCell = "Bin1" Or ValueCell = "Bin2" Or ValueCell = "Bin3" Or _
ValueCell = "Bin4" Or ValueCell = "Bin5" Then
.Range("A1:G1").Copy Destination:=Worksheets("Sheet4").Range("A1")
End If
Next
Next
End With
End Sub
Possible further change
Are the loops really independent? To me it looks as though you could merge them into a single loop.
New section added in response to exchange of comments
Consider the code in your question:
You have six double loops.
In every case, the outer loop is For iCol = 1 to 1. That is, you only examine column "A" although you imply you would examine more columns if the code was faster.
The inner loop is For iRow = 1 to №. № is 1 in the first loop, 2 in the second and 6 in the sixth loop. Again you imply you would examine more rows if the code was faster.
The action for each loop depends on the value of №.
Table showing effect of № of action:
Value
of № Cells examined Values checked for Range moved
1 A1 "Bin1" ... "Bin6" A1:G1
2 A1, A2 "Bin2" ... "Bin6" A2:G2
3 A1, A2, A3 "Bin3" ... "Bin6" A3:G3
4 A1, A2, ... A4 "Bin4" ... "Bin6" A4:G4
5 A1, A2, ... A5 "Bin5", "Bin6" A5:G5
6 A1, A2, ... A6 "Bin6" A6:G6
That is, in double loop №, you examine cells A1 to A№, check for values "Bin№" to "Bin6" and if found, you copy Sheets("Sheet3").Range("A№:G№") to Sheets("Sheet4").Range("A№).
In your text and example data, you refer to "text2" instead of "Bin2". I do not understand what you are trying to do. Below, I introduce some more VBA which may help you create the code you want. If it does not, you will have to add a new section to your question explaining in English what you are trying to do.
New syntax 1
Consider:
For iRow = 1 to 6
:
.Range("A6:G6").Copy Destination:=Worksheets("Sheet4").Range("A6")
:
Next
"A6:G6" and "A6" are strings that you can build at runtime.
Now consider:
For iRow = 1 to iRowMax
:
.Range("A" & iRowMax & ":G" & iRowMax)).Copy _
Destination:=Worksheets("Sheet4").Range("A" & iRowMax)
:
Next
According to the value of iRowMax this gives:
iRow Statement
1 .Range("A1:G1")).Copy Destination:=Worksheets("Sheet4").Range("A1")
2 .Range("A2:G2")).Copy Destination:=Worksheets("Sheet4").Range("A2")
3 .Range("A3:G3")).Copy Destination:=Worksheets("Sheet4").Range("A3")
New syntax 2
Another way of changing a range at runtime is to replace:
.Range(string)
with
.Range(.Cells(RowTop,ColLeft),.Cells(RowBottom,ColRight))
With this syntax you can easily specify a rectangle of the size required.
New syntax 3
Consider:
For i = 1 to 5
If this(i) = that Then
Do something fixed
Exit For
End If
Next
' Exit For statement jumps to here
In this loop, I am testing five values. If any match, I do something. If I get a match on the first value, I do not need to check the other values. Exit For allows me to jump out of the For-Loop. If there are nested For-Loops, Exit For only exits the inner loop
New syntax 4
"Bin1", "Bin2" and so on can also be created at runtime.
iRowMax = 4
For iRow = 1 to iRowMax
For iBin = iRowMax to 6
If ValueCell = "Bin" & iBin Then
' Move Range
Exit For
End If
Next
' Exit For statement jumps to here
Next
With iRow = 4, the inner For-Loop sets iBin to 4, 5 and 6. This sets "Bin" & iBin to "Bin4", "Bin5" and "Bin6".
So:
For BinNum = iRowMax to 6
If ValueCell = "Bin" & BinNum Then
' Move Range
Exit For
End If
Next
is the same as:
If ValueCell = "Bin4" Or ValueCell = "Bin5" Or ValueCell = "Bin6" Then
' Move Range
End If
This new code is more complicated and is more difficult to understand than the original, but it may be what you need.
Summary
I have shown you different ways of changing what happens depending on the value of iRow. I hope one of them will allow you to build the routine you want.
I have not tested it but I think this does the same as all six loops in your original code:
Option Explicit
Sub Macro1()
Dim iBin as Long
Dim iCol As Long
Dim iRow As Long
Dim iRowMax as Long
Dim ValueCell as String
Application.ScreenUpdating = False
With Sheets("Sheet3")
For iRowMax = 1 to 6
For iCol = 1 To 1 ' This could be replaced by iCol = 1 at the top
For iRow = 1 To iRowMax
ValueCell = .Cells(iRow, iCol).Value
For iBin = iRowMax to 6
If ValueCell = "Bin" & iBin Then
.Range("A" & iRowMax & ":G" & iRowMax)).Copy _
Destination:=Worksheets("Sheet4").Range("A" & iRowMax)
End If
Next iBin
Next iRow
Next iCol
End With
End Sub
Note: only removing all the Select statements makes this code faster than yours. The other changes make it smaller and very slightly slower because I have two extra For-Loops and I am building strings at runtime.
Related
I have a data that is in 1 column with all the data together i.e, date, comment and amount. so A1 is date, A2 is comment and A3 is amount, and the cycle goes on.
I wanted to transpose this into a table format so basically the data in A1 is cut and pasted into B1, A2 is cut and pasted into C1, A3 is cut and pasted into D1 and continues on ... A4->B2, A5->C2, A6->D2
I have recorded a macro and it was a long list. Is it possible to simplify this as it is a repeating action ? The action just need to stop when it has copied the last data in column A.
kind regards,
Range("A1").Select
Selection.Cut
Range("B1").Select
ActiveSheet.Paste
Range("A2").Select
Selection.Cut
Range("C1").Select
ActiveSheet.Paste
Range("A3").Select
Selection.Cut
Range("D1").Select
ActiveSheet.Paste
Range("A4").Select
Selection.Cut
Range("B2").Select
ActiveSheet.Paste
Range("A5").Select
Selection.Cut
Range("C2").Select
ActiveSheet.Paste
Range("A6").Select
Selection.Cut
Range("D2").Select
ActiveSheet.Paste
Range("A7").Select
Selection.Cut
Range("B3").Select
ActiveSheet.Paste
Range("A8").Select
Selection.Cut
Range("C3").Select
ActiveSheet.Paste
Range("A9").Select
Selection.Cut
Range("D3").Select
ActiveSheet.Paste
use macro recorder to see the vb codes
If you have Excel 2021 or Excel 365 with the SEQUENCE function and dynamic arrays, you can simply use the formula
=INDEX(DCA,SEQUENCE(ROWS(DCA)/3,3))
where DCA is either a named range or the name of the table of values in column A.
Enter the formula in some cell, and the results will spill into the columns and rows.
You can do it using VBA.
The code below assumes your data starts in A2 with a column header in A1 on Sheet6 and that your output will start at Sheet6!D1
Change references as needed
Option Explicit
Sub column2rows()
Dim rRes As Range, vSrc, vRes
Dim I As Long, J As Long, K As Long
With ThisWorkbook.Worksheets("Sheet6")
vSrc = Range(.Cells(1, 1), .Cells(.Rows.Count, 1).End(xlUp))
End With
ReDim vRes(0 To (UBound(vSrc, 1)) / 3, 1 To 3)
vRes(0, 1) = "Date"
vRes(0, 2) = "Comment"
vRes(0, 3) = "Amount"
I = 2
For K = 1 To UBound(vSrc, 1) / 3
For J = 1 To 3
vRes(K, J) = vSrc(I, 1)
I = I + 1
Next J
Next K
Set rRes = ThisWorkbook.Worksheets("Sheet6").Cells(1, 4).Resize(UBound(vRes, 1) + 1, UBound(vRes, 2))
Application.ScreenUpdating = False
With rRes
.EntireColumn.Clear
.Value = vRes
.Style = "output" 'may need to change if language <> English
.EntireColumn.AutoFit
End With
End Sub
I have recorded a macro that lets me split a persons monthly schedule into weeks.
Sub HoursSplit()
Selection.PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
ActiveCell.Offset(0, 1).Select
Application.CutCopyMode = False
ActiveCell.FormulaR1C1 = "=RC[-1]/4"
ActiveCell.Offset(0, 1).Select
Application.CutCopyMode = False
ActiveCell.FormulaR1C1 = "=RC[-1]"
ActiveCell.Offset(0, 1).Select
Application.CutCopyMode = False
ActiveCell.FormulaR1C1 = "=RC[-1]"
ActiveCell.Offset(0, -3).Select
Application.CutCopyMode = False
ActiveCell.FormulaR1C1 = "=RC[1]"
End Sub
As an example:
Person
Month 2
Month 3
Person 1
173
173
Effectively:
I select the monthly hours im looking to split (i.e Month 2)
copy it
select a cell elsewhere with no data in it
Hit Cntrl + Shift + C
In the case above, it gives me
Cell 1
Cell 2
Cell 3
Cell 4
43.25
43.25
43.25
43.25
Thing is, this only works for a single person/cell, making splitting everyones hourshours up into weeks tedious.
How can i modify the above to work for an entire column range selection (i.e Multiple people at once for the same month)?
Another way you can do what you want (and should be faster).
Public Sub HoursSplit_Test()
Dim cell As Range
For Each cell In Selection
cell.Resize(, 4).Value = cell.Value / 4
Next cell
End Sub
Was able to solve my own issue eventually.
Public Sub HoursSplit_Test()
Dim cell As Excel.Range
For Each cell In Selection
cell.Value = cell.Value / 4
cell.Copy
cell.Offset(0, 1).PasteSpecial
cell.Offset(0, 2).PasteSpecial
cell.Offset(0, 3).PasteSpecial
Next cell
End Sub
Needed to write code for copy paste date in single column.
by means of that there are n numbers of columns and needed to paste those in single column.
code that i tried but not working well
Sub Macro4()
'
' Macro4 Macro
'
'
Range("C3").Select
Selection.Copy
Range("B4:B12").Select
ActiveSheet.Paste
Range("E3").Select
Application.CutCopyMode = False
Selection.Copy
Range("D4:D12").Select
ActiveSheet.Paste
Range("G3").Select
Application.CutCopyMode = False
Selection.Copy
Range("F4:F8").Select
ActiveSheet.Paste
Range("I3").Select
Application.CutCopyMode = False
Selection.Copy
Range("H4:H10").Select
ActiveSheet.Paste
Range("B4:C12").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Sheet5").Select
Range("D2").Select
ActiveSheet.Paste
Sheets("Sheet4").Select
Range("D4:E12").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Sheet5").Select
Range("D11").Select
ActiveSheet.Paste
Sheets("Sheet4").Select
Range("F4:G8").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Sheet5").Select
Range("D20").Select
ActiveSheet.Paste
Sheets("Sheet4").Select
Range("H4:I10").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Sheet5").Select
Range("D25").Select
ActiveSheet.Paste
End Sub
i am posting image to show you which type of input i have and what type of output i needed. please help me to crack it ...Thanks
Welcome to StackOverflow. And welcome to VBA. Please study the code example below. it will do what you described.
Option Explicit ' always use this statement
Sub LoopColumns()
' always identify and declare your worksheets
Dim WsS As Worksheet ' Source sheet
Dim WsD As Worksheet ' Destination sheet
Dim CopyRange As Range
Dim C As Long ' column number
Dim Rld As Long ' last row in WsD
Set WsS = ActiveSheet ' better identify the sheet by name
Set WsS = Worksheets("Sheet1") ' this is the sheet I used
Set WsD = Worksheets("Sheet5") ' better give the sheet a descriptive name
For C = 1 To 6 Step 2 ' select columns 1, 3 and 5 in turn
' specify the range starting in row 4 of the looped column
' and end at the end of that column, offset by 1
Set CopyRange = WsS.Range(WsS.Cells(4, C), _
WsS.Cells(WsS.Rows.Count, C).End(xlUp).Offset(0, 1))
' determine the row below the last used row in WsD
Rld = WsD.Cells(WsD.Rows.Count, 1).End(xlUp).Row + 1
If Rld < 3 Then Rld = 3 ' start from row 3 3
' paste to column A below the last used row
CopyRange.Copy Destination:=WsD.Cells(Rld, "A")
Next C
End Sub
Change the ranges and try:
Option Explicit
Sub test()
Dim LastRowCol As Long, LastRowOut As Long, i As Long, StartColumn As Long, Endcolumn As Long
StartColumn = 2
Endcolumn = 6
With ThisWorkbook.Worksheets("Sheet1")
For i = StartColumn To Endcolumn Step 2
LastRowCol = .Cells(.Rows.Count, i).End(xlUp).Row
LastRowOut = .Cells(.Rows.Count, "J").End(xlUp).Row
.Range(.Cells(4, i), .Cells(LastRowCol, i + 1)).Copy .Range("J" & LastRowOut + 1)
Next i
End With
End Sub
Result:
I have a table where I need to find the elements present in different samples.
For every sample, the no of iterations is a variable - I can have two rows of sample 1 and 3 rows of sample2 or 5 rows of sample4. the number of columns which are the elements can also be different. I have considered 3 samples and 17 elements in this case.
I need to filter based on the sample. say sample 1. Then the average needs to be calculated for all the entries of sample 1. Then below that sample 2 values need to be displayed and the average for all the entries of sample 2 should be calculated.
I am a beginner in vba and hence the code I used is not able to do it for dynamic range of values. Also, I can only calculate the average using macro recorder. I am not aware how to combine these two codes into one. I tried to search a lot on this topic
I have included my codes as well.
Any help would be much appreciated!!! Thank you
Sub sorttable()
Dim j As Long 'row variable
On Error GoTo Err_Execute
Dim i As Long
'Start search in row 1 in sheet1
j = 1
'Column counter for sheet2
i = 1
While Len(Range("A" & CStr(j)).Value) > 0
If Range("A" & CStr(j)).Value = "Sample1" Then
Range(Range("A" & CStr(j)), Range("A" & CStr(j)).End(xlToRight)).Select
Selection.Copy
Sheets("Sheet2").Select
Sheet2.Cells(i, 1).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
'Cells(j + 1, 1) = "=AVERAGE(A1:C" & j - 1 & ")" 'used to calculate avg
i = i + 1
Sheets("Sheet1").Select
ElseIf Range("A" & CStr(j)).Value = "Sample2" Then
Range(Range("A" & CStr(j)), Range("A" & CStr(j)).End(xlToRight)).Select
Selection.Copy
Sheets("Sheet2").Select
Sheet2.Cells(i, 1).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
i = i + 1
Sheets("Sheet1").Select
ElseIf Range("A" & CStr(j)).Value = "Sample3" Then
Range(Range("A" & CStr(j)), Range("A" & CStr(j)).End(xlToRight)).Select
Selection.Copy
Sheets("Sheet2").Select
Sheet2.Cells(i, 1).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
i = i + 1
Sheets("Sheet1").Select
End If
j = j + 1
Wend
Application.CutCopyMode = False
MsgBox "the values have been extracted"
Exit Sub
Err_Execute:
MsgBox "Error Occured"
End Sub
'code- part of it for calculating the average
Application.CutCopyMode = False
Selection.AutoFill Destination:=Range("A9:B9"), Type:=xlFillDefault
Range("A9:B9").Select
Range("B9").Select
Selection.ClearContents
ActiveCell.FormulaR1C1 = "= AVERAGE(R[-2]C,R[-1]C)"
Range("B9").Select
Selection.AutoFill Destination:=Range("B9:R9"), Type:=xlFillDefault
Range("B9:R9").Select
Range("A11").Select
Sheets("Sheet2").Select
Range("A27").Select
Sheets("Sheet1").Select
Range("A8:R10").Select
Selection.Copy
Sheets("Sheet2").Select
Range("A11").Select
ActiveSheet.Paste
Range("A14").Select
Application.CutCopyMode = False
Selection.Style = "Normal 2"
ActiveCell.FormulaR1C1 = "Average"
Range("B14").Select
ActiveCell.FormulaR1C1 = "= AVERAGE(R[-3]C:R[-1]C)"
Range("B14").Select
Selection.AutoFill Destination:=Range("B14:R14"), Type:=xlFillDefault
Range("B14:R14").Select
Range("A16").Select
End Sub
It looks like you've recorded your macro as a start, then tried to modify it from there. This is an excellent first step, so now there are things to be aware of:
The macro recorder captures many, many things that are unnecessary, so don't use Select or Activate.
Since your data may not be the same for each sample group, your code has to take that into account. Review the sample code below and notice that it loops to figure out how many rows are in a sample group, then dynamically fills in the formula for the columns of that group.
Option Explicit
Sub SortTable()
Dim ws As Worksheet
Set ws = ActiveSheet
Dim numSampleRows As Long
numSampleRows = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row - 1
Dim sampleRow As Range
Set sampleRow = ws.Range("A2")
Dim i As Long
Dim numSamplesInGroup As Long
Dim currentSampleLabel As String
Dim numSampleColumns As Long
Dim avgRow As Long
Dim avgCol As Long
For i = 1 To (numSampleRows + 1)
'--- look at the sample labels to determine how
' many are in this group
If numSamplesInGroup = 0 Then
'--- this is the start of a sample group
currentSampleLabel = sampleRow.Offset(0, 0)
numSamplesInGroup = 1
ElseIf currentSampleLabel = sampleRow.Offset(0, 0) Then
'--- continue to count the samples in the group
numSamplesInGroup = numSamplesInGroup + 1
Else
'--- we've reached the end of the sample group
' so insert two empty rows here
sampleRow.EntireRow.Insert
sampleRow.EntireRow.Insert
Debug.Print sampleRow.Address
'--- create the AVERAGE formula for each populated column
' ASSUMES all the columns are consistent for each sample group
avgRow = sampleRow.Offset(-2, 0).Row
ws.Cells(avgRow, 1) = "Average"
numSampleColumns = ws.Cells(avgRow - 1, ws.Columns.Count).End(xlToLeft).Column
For avgCol = 1 To (numSampleColumns - 1)
sampleRow.Offset(-2, avgCol).FormulaR1C1 = _
"=AVERAGE(R" & _
avgRow - numSamplesInGroup & _
"C" & avgCol + 1 & _
":R" & avgRow - 1 & "C" & avgCol + 1 & ")"
Next avgCol
'--- reset for the next loop
currentSampleLabel = sampleRow.Offset(0, 0)
numSamplesInGroup = 0
End If
'--- move down one row
Set sampleRow = sampleRow.Offset(1, 0)
Next i
End Sub
I have a functioning macro that copy pastes the static values of live data from the live data sheet (Sheet), onto a separate sheet (Sheet2) every second. The code is below. For your information, Range("B2:B2195") are stock codes while Range("H2:H2195") are stock quotes.
Sub copypaste_RECENT()
Dim ab As Integer
Worksheets("Sheet").Range("B2:B2195").Copy
With Sheets("Sheet2")
.Range("B1").PasteSpecial Transpose:=True
ab = .Cells(.Rows.Count, 1).End(xlUp).Row + 1
.Cells(1, 1).Value = "Time"
.Cells(ab, 1).Value = Now
Worksheets("Sheet").Range("H2:H2195").Copy
.Range("B" & ab).PasteSpecial Paste:=xlPasteValues, Transpose:=True
End With
Application.OnTime Now + TimeSerial(0, 0, 1), "copypaste_RECENT"
End Sub
My next step is one that im having trouble with. I would like to record the difference between the stock quotes. This means calculating the difference between a certain cell and the cell above it and recording this difference onto a separate sheet (Sheet3). This would run simultaneously to the code above so I've tried to include an additional code after End With and before the Application. The code is below.
Worksheets("Sheet").Range("B2:B2195").Copy
With Sheets("Sheet3")
.Range("B1").PasteSpecial Transpose:=True
Dim xy As Long, yz As Long
ab = .Cells(.Rows.Count, 1).End(xlUp).Row + 1
bc = .Cells(1, .Columns.Count).End(x1toleft).Column + 1
.Cells(1, 1).Value = "Time"
.Cells(ab, 1).Value = Now
xy = Worksheets("Sheet2").Cells(.Rows.Count, 1).End(x1up).Row
yz = Worksheets("Sheet2").Cells(.Rows.Count, 1).End(x1up).Row.Offset(-1, 0)
For ab = 1 To Cells(Rows.Count, 1).End(x1up).Row + 1
For bc = 1 To Cells(1, Columns.Count).End(x1toleft).Column + 1
.Cells(ab, bc).Value = xy - yz
Next ab
Next bc
End With
I'm quite new to VBA and I know this is completely wrong. I've been struggling for a while but I hope it makes some sort of sense.
Thanks in advance!
Grant
EDIT1: This is a simple computation that calculates the difference between a certain cell and the cell above it and records this value onto a separate sheet. This computation is done for every cell in the range.
I am not comletely cleat what you like to achieve. Is it alog, so you write consecutive lines of copied and computed entries, or is is just some computation. So depending on this you have at least three options:
1) copy/paste with math functions
using the copy/past with the special mathematical functions (add, substract, multiply, divide)
2) formulas
you enter in sheet3 the formuala into B2 =+sheet2!B4-sheet2!B3 which will compute this automatically.
3) compute an store the difference
make a computation as above and copy/paste the result to the final destination.
EDIT
Excel is designed to do computations! So why do you want to redo this?
You can do all of the mentioned solutions as VBA. The same way as you did is with your copy and paste above.
Here is a short makro which shows what I mean.
Sub Makro1()
'
' Makro1 Makro
'
'
ActiveCell.FormulaR1C1 = "Line 1"
Range("B1").Select
ActiveCell.FormulaR1C1 = "8"
Range("C1").Select
ActiveCell.FormulaR1C1 = "5"
Range("D1").Select
ActiveCell.FormulaR1C1 = "6"
Range("E1").Select
ActiveCell.FormulaR1C1 = "4"
Range("F1").Select
ActiveCell.FormulaR1C1 = "6"
Range("G1").Select
ActiveCell.FormulaR1C1 = "3"
Range("A2").Select
ActiveCell.FormulaR1C1 = "12"
Range("A2").Select
ActiveCell.FormulaR1C1 = "Line 2"
Range("B2").Select
ActiveCell.FormulaR1C1 = "15"
Range("C2").Select
ActiveCell.FormulaR1C1 = "456"
Range("D2").Select
ActiveCell.FormulaR1C1 = "23"
Range("E2").Select
ActiveCell.FormulaR1C1 = "42"
Range("F2").Select
ActiveCell.FormulaR1C1 = "45"
Range("G2").Select
ActiveCell.FormulaR1C1 = "77"
Range("A1:G1").Select
Selection.Copy
Range("A5").Select
ActiveSheet.Paste
Range("B2:G2").Select
Application.CutCopyMode = False
Selection.Copy
Range("B5").Select
Selection.PasteSpecial Paste:=xlPasteAll, Operation:=xlSubtract, _
SkipBlanks:=False, Transpose:=False
End Sub