I am just trying a simple copy from one Excel sheet to another but the program seems to be taking forever.
n = WorksheetFunction.CountA(WAEnv.Range("a4:a" & WAEnv.Rows.Count))
ro = 3
For i = 4 To n + 4
If Len(Trim(WAEnv.Cells(i, 1).Value)) > 0 Then
ro = ro + 1
WAPatch.Cells(ro, 1).RowHeight = WAEnv.Cells(i, 1).RowHeight
WAPatch.Cells(ro, 1).Value = Trim(WAEnv.Cells(i, 1).Value)
WAPatch.Cells(ro, 2).Value = Trim(WAEnv.Cells(i, 2).Value)
WAPatch.Cells(ro, 3).Value = Trim(WAEnv.Cells(i, 3).Value)
WAPatch.Cells(ro, 4).Value = Trim(WAEnv.Cells(i, 4).Value)
WAPatch.Cells(ro, 5).Value = Trim(WAEnv.Cells(i, 5).Value)
End If
Next i
Is there a faster or more efficient way to do this?
If objective to set RowHeight could be sacrificed, then may try the following code (obviously after modifying sheets, ranges particulars to your requirement)
Sub test()
Dim WAEnv As Worksheet, WAPatch As Worksheet, Rng As Range
Dim SrcArr As Variant, DstArr() As Variant
Dim Rw As Long, cl As Range
Dim Xrow As Long, Xcol As Long, Lastrow As Long
Dim Chunk60K As Long
Dim tm As Double
tm = Timer
Set WAEnv = ThisWorkbook.Sheets("Sheet3")
Set WAPatch = ThisWorkbook.Sheets("Sheet4")
Set Rng = WAEnv.Range("A4:E" & WAEnv.Cells(Rows.Count, 1).End(xlUp).Row)
SrcArr = Rng.Value
Xrow = 1
Chunk60K = 0
For Rw = 1 To UBound(SrcArr, 1)
If SrcArr(Rw, 1) > 0 Then
ReDim Preserve DstArr(1 To 5, 1 To Xrow)
For Xcol = 1 To 5
DstArr(Xcol, Xrow) = SrcArr(Rw, Xcol)
Next Xcol
If Xrow = 60000 Then ' To Overcome 65K limit of Application.Transpose
WAPatch.Range("A" & Chunk60K * 60000 + 3).Resize(UBound(DstArr, 2), UBound(DstArr, 1)).Formula = Application.Transpose(DstArr)
Chunk60K = Chunk60K + 1
Xrow = 1
ReDim DstArr(1 To 5, 1 To 1)
Debug.Print "Chunk: " & Chunk60K & " Seconds Taken: " & Timer - tm
Else
Xrow = Xrow + 1
End If
End If
Next Rw
WAPatch.Range("A" & Chunk60K * 60000 + 3).Resize(UBound(DstArr, 2), UBound(DstArr, 1)).Formula = Application.Transpose(DstArr)
Debug.Print "Completed at Chunk: " & Chunk60K & " Total Seconds Taken: " & Timer - tm
End Sub
Code takes around 7-8 seconds to process around 300 K rows (around 1/2 of it filtered out)
Since I personally don't prefer to keep calculations, event processing and screen updating off (in normal cases) i haven't added that standard lines. However you may use these standard techniques, depending on the working file condition.
Edit: adding code including Row height setting (unstable after 150 K)
Sub test4()
Dim WAEnv As Worksheet, WAPatch As Worksheet, Rng As Range
Dim SrcArr As Variant, DstArr() As Variant
Dim Rw As Long, cl As Range
Dim Xrow As Long, Xcol As Long, Lastrow As Long
Dim Chunk60K As Long
Dim tm As Double
tm = Timer
Set WAEnv = ThisWorkbook.Sheets("Sheet3")
Set WAPatch = ThisWorkbook.Sheets("Sheet4")
'n = WorksheetFunction.CountA(WAEnv.Range("a4:a" & WAEnv.Rows.Count))
Lastrow = WAEnv.Cells(Rows.Count, 1).End(xlUp).Row
Debug.Print Lastrow
Xrow = 1
Chunk60K = 0
For Rw = 4 To Lastrow
Set Rng = WAEnv.Range("A" & Rw & ":E" & Rw)
If Rng(1, 1).Value > 0 Then
ReDim Preserve DstArr(1 To 5, 1 To Xrow)
Xcol = 1
For Each cl In Rng.Columns.Cells
DstArr(Xcol, Xrow) = cl.Value
Xcol = Xcol + 1
Next cl
WAPatch.Cells(Xrow, 1).RowHeight = Rng(1, 1).RowHeight
If Xrow = 60000 Then ' To Overcome 65K limit of Application.Transpose
WAPatch.Range("A" & Chunk60K * 60000 + 3).Resize(UBound(DstArr, 2), UBound(DstArr, 1)).Formula = Application.Transpose(DstArr)
Chunk60K = Chunk60K + 1
Xrow = 1
ReDim DstArr(1 To 5, 1 To 1)
Debug.Print "Chunk: " & Chunk60K & " Seconds Taken: " & Timer - tm
Else
Xrow = Xrow + 1
End If
End If
Next Rw
WAPatch.Range("A" & Chunk60K * 60000 + 3).Resize(UBound(DstArr, 2), UBound(DstArr, 1)).Formula = Application.Transpose(DstArr)
Debug.Print "Completed at Chunk: " & Chunk60K & " Total Seconds Taken: " & Timer - tm
End Sub
n = WorksheetFunction.CountA(WAEnv.Range("a4:a" & WAEnv.Rows.Count))
ro = 3
For i = 4 To n + 4
If Len(Trim(WAEnv.Cells(i, 1).Value)) > 0 Then
ro = ro + 1
WAEnv.range("A" & i & ":E" & i).copy
WAPatch.range("A" & ro & ":E" & ro).pastespecial xlpastevalues
With WAPatch.range("A" & ro & ":E" & ro)
.Value = Evaluate("IF(ROW(" & .Address & "),CLEAN(TRIM(" & .Address & ")))")
End With
End if
Next
Copy and past the row of data in one go then trim the resulting data.
Also if you have a large number of formulas in the sheet it will slow down as it recalculates, if this is the case you can try setting calcs to manual at the start of your code and back to auto at the end.
I'd experiment with the times achieved without looping at all. Copy the entire sheet across, and then on the new sheet sort by one column descending to put your blanks to the bottom. If you care about the sort order then shrink your range and sort them again.
Admittedly that might not be quicker, but if you don't need the rows sorted as they originally were then you'll only need the one sort.
Finally, if you have a high proportion of blanks, and you're not coming back to the original sheet, do the sorting there before copying. Or apply a filter and delete the offending rows, though I find this a little more finicky.
Related
im trying to make a vba code that will detect when Active balancing is on ( A value in cell ) and then copy the previous tension value, and simillarly do the same at the end of Active balancing to copy the next tension value. (see picture for more explanation).
im planing to show those values in another sheet
thanks to the help of Mr.PeterT i modified his code to do it but i couldn't succeed. thanks for you help and mentoring guys!
image of values i want to extract
Option Explicit
Sub find_balanced_cells_and_tensions()
FindWith "A"
End Sub
Sub FindWith(checkValue As Variant)
Dim destinationSheet As Worksheet
Set destinationSheet = ThisWorkbook.Sheets.Add
destinationSheet.Name = "Equilibrage.actif.info"
Dim destRow As Long
destRow = 1
Dim sourceSheet As Worksheet
Set sourceSheet = ThisWorkbook.Sheets("Equilibrage.passif")
Dim lastRow As Long
Dim lastColumn As Long
lastRow = sourceSheet.Cells(sourceSheet.Rows.Count, 1).End(xlUp).Row
lastColumn = sourceSheet.Cells(1, sourceSheet.Columns.Count).End(xlToLeft).Column
Dim i As Long
Dim j As Long
For j = 1 To lastColumn
For i = 2 To lastRow
If sourceSheet.Cells(i, j).Value = checkValue _
& sourceSheet.Cells(i + 1, j).Value = checkValue Then
sourceSheet.Cells(i - 1, j - 1).Copy _
Destination:=destinationSheet.Range("A" & destRow)
destRow = destRow + 1
ElseIf sourceSheet.Cells(i, j).Value = checkValue _
& sourceSheet.Cells(i + 1, j).Value <> checkValue Then
sourceSheet.Cells(i + 1, j - 1).Copy _
Destination:=destinationSheet.Range("B" & destRow)
destRow = destRow + 1
Exit For 'immediately skip to the next row
End If
Next i
Next j
End Sub
Untested but should be close.
I will test if you can share a sample dataset.
Sub find_balanced_cells_and_tensions()
FindWith "A"
End Sub
Sub FindWith(checkValue As Variant)
Dim sourceSheet As Worksheet
Dim destinationSheet As Worksheet
Dim destRow As Long, lastRow As Long, lastColumn As Long, valCount As Long
Dim i As Long, j As Long, preVal, postval, cellLabel, dt, tm
Set sourceSheet = ThisWorkbook.Sheets("Equilibrage.passif")
Set destinationSheet = ThisWorkbook.Sheets.Add()
destinationSheet.Name = "Equilibrage.actif.info"
destRow = 1
lastRow = sourceSheet.Cells(sourceSheet.Rows.Count, 1).End(xlUp).Row
lastColumn = sourceSheet.Cells(1, sourceSheet.Columns.Count).End(xlToLeft).Column
For j = 4 To lastColumn Step 2 'only process relevant columns
i = 3
Do 'from 3 to lastrow-1 to allow for -1 at top and +1 at bottom
If sourceSheet.Cells(i, j).Value = checkValue Then
dt = sourceSheet.Cells(i - 1, 1).Value 'collect start info
tm = sourceSheet.Cells(i - 1, 2).Value
cellLabel = sourceSheet.Cells(1, j).Value
preVal = sourceSheet.Cells(i - 1, j - 1).Value
valCount = 1 'how many values in this run?
Do While sourceSheet.Cells(i, j).Offset(valCount).Value = checkValue
valCount = valCount + 1
Loop
postval = sourceSheet.Cells(i + valCount, j - 1).Value
destinationSheet.Cells(destRow, 1).Resize(1, 5).Value = _
Array(dt, tm, cellLabel, preVal, postval)
destRow = destRow + 1
i = i + valCount
End If
i = i + 1
Loop While i < lastRow
Next j
End Sub
So after countless hit and miss and the help of Tim Williams and Funthomas, i arrived to this code that does the job plus some things.
the worksheet to get the values from is this one :
Value source
And the result of the code is like this :
Results
the final code is like this :
Option Explicit
Sub find_balanced_cells_and_tensions_A()
FindWith "A" ' we can replace A by any value we want to look for here
End Sub
Sub FindWith(checkValue As Variant)
Dim destinationSheet As Worksheet
Set destinationSheet = ThisWorkbook.Sheets.Add
destinationSheet.Name = "Equilibrage.actif.info"
'___ variables to track cells where will put our extacted values _______
Dim destRow As Long
destRow = 1
Dim destRow2 As Long
destRow2 = 1
'______ source sheet where we take our values from ___________
Dim sourceSheet As Worksheet
Set sourceSheet = ThisWorkbook.Sheets("Equilibrage.passif")
'_____ defining the end of columns and rows to end scaning for values _____________
Dim lastRow As Long
Dim lastColumn As Long
lastRow = sourceSheet.Cells(sourceSheet.Rows.Count, 1).End(xlUp).Row
lastColumn = sourceSheet.Cells(1, sourceSheet.Columns.Count).End(xlToLeft).Column
Dim i As Long
Dim j As Long
For j = 1 To lastColumn
For i = 2 To lastRow
'_____this part is to detect the start of balancing and taking the tension value of the previous row______________________
If sourceSheet.Cells(i, j).Value = checkValue _
And sourceSheet.Cells(i - 1, j).Value = 0 Then
sourceSheet.Cells(i - 1, j - 1).Copy _
Destination:=destinationSheet.Range("E" & destRow)
Range("A" & destRow).Value = sourceSheet.Cells(1, j)
Range("B" & destRow).Value = "was actively balanced at"
Range("C" & destRow).Value = sourceSheet.Cells(i, 2)
Range("D" & destRow).Value = "from"
Range("F" & destRow).Value = "to"
destRow = destRow + 1
'______ this condition is for when the balancing starts at the first row of the table so we take the present tension instead of the previous ___________
ElseIf sourceSheet.Cells(i, j).Value = checkValue _
And sourceSheet.Cells(i - 1, j).Value <> checkValue _
And sourceSheet.Cells(i - 1, j).Value <> 0 Then
sourceSheet.Cells(i, j - 1).Copy _
Destination:=destinationSheet.Range("E" & destRow)
Range("A" & destRow).Value = sourceSheet.Cells(1, j)
Range("B" & destRow).Value = "was actively balanced at"
Range("C" & destRow).Value = sourceSheet.Cells(i, 2)
Range("D" & destRow).Value = "from"
Range("F" & destRow).Value = "to"
destRow = destRow + 1
End If
'_____to find the next tension value after the end of balancing _____________
If sourceSheet.Cells(i, j).Value = checkValue _
And sourceSheet.Cells(i + 1, j).Value <> checkValue _
And IsEmpty(sourceSheet.Cells(i + 1, j).Value) = False Then
sourceSheet.Cells(i + 1, j - 1).Copy _
Destination:=destinationSheet.Range("G" & destRow2)
Range("H" & destRow2).Value = "at"
Range("I" & destRow2).Value = sourceSheet.Cells(i + 1, 2)
destRow2 = destRow2 + 1
'_____in case the balancing ends at the last row we take the present tension as the next one doesnt exist _____________
ElseIf sourceSheet.Cells(i, j).Value = checkValue _
And IsEmpty(sourceSheet.Cells(i + 1, j).Value) = True Then
sourceSheet.Cells(i, j - 1).Copy _
Destination:=destinationSheet.Range("G" & destRow2)
Range("H" & destRow2).Value = "at"
Range("I" & destRow2).Value = sourceSheet.Cells(i, 2)
destRow2 = destRow2 + 1
End If
Next i
Next j
'_____ Cells modification and formating _________________
Range("C:C").NumberFormat = "hh:mm:ss"
Range("I:I").NumberFormat = "hh:mm:ss"
Range("E:E").Style = "Normal"
Range("G:G").Style = "Normal"
Range("A:K").Font.Size = 14
Range("E:E").Font.Bold = True
Range("G:G").Font.Bold = True
Worksheets("Equilibrage.actif.info").Columns.AutoFit
End Sub
I have written a piece of code that does reconciliation:
The first part checks between columns.
Works absolutely fine on upto 100k Rows, then simply freezes on anything bigger. Is the an optimal way to write this? Should I be using a scripting dictionary for the reconciliation too? Ive been off VBA for a while now and I am pretty rusty! Thanks for reading and helping.
Sub AutoRecon()
Worksheets("Main_Recon").Select
Dim i As Long, _
LRa As Long, _
LRb As Long, _
rowx As Long
LRa = Range("A" & Rows.Count).End(xlUp).Row
LRb = Range("G" & Rows.Count).End(xlUp).Row
rowx = 2
Application.ScreenUpdating = False
For i = 2 To LRa
If Range("A" & i).Errors.Item(xlNumberAsText).Value = True Then
Range("A" & i).Value = "N" & Range("A" & i).Value
rowx = rowx + 1
End If
Next i
rowx = 2
For i = 2 To LRb
If Range("G" & i).Errors.Item(xlNumberAsText).Value = True Then
Range("G" & i).Value = "N" & Range("G" & i).Value
rowx = rowx + 1
End If
Next i
rowx = 2
For i = 2 To LRa
If IsError(Application.Match(Range("A" & i).Value, Range("G2:G" & LRb), 0)) Then
Range("O" & rowx).Value = Range("A" & i).Value
rowx = rowx + 1
End If
Next i
rowx = 2
For i = 2 To LRb
If IsError(Application.Match(Range("G" & i).Value, Range("A2:A" & LRa), 0)) Then
Range("S" & rowx).Value = Range("G" & i).Value
rowx = rowx + 1
End If
Next i
Application.ScreenUpdating = True
End Sub
This takes too long.
The issue is that you run the loop 4 times, but you can combine 2 loops.
You can gain some speed in the process using arrays to read/write. Every read/write action to a cell needs a lot of time. So the idea is to read all data cells into an array DataA at once (only 1 read action) then process the data in the array and then write it back to the cells at once (only 1 write action). So if you have 100 rows you save 99 read/write actions.
So you would end up with something like below. Note this is untested, so backup before running this.
Option Explicit
Public Sub AutoRecon()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Main_Recon")
Application.ScreenUpdating = False
'find last rows of columns
Dim LastRowA As Long
LastRowA = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim LastRowG As Long
LastRowG = ws.Cells(ws.Rows.Count, "G").End(xlUp).Row
'read data into array
Dim DataA() As Variant 'read data from column A into array
DataA = ws.Range("A1", "A" & LastRowA).Value
Dim DataG() As Variant 'read data from column G into array
DataG = ws.Range("G1", "G" & LastRowG).Value
Dim iRow As Long
For iRow = 2 To Application.Max(LastRowA, LastRowG) 'combine loop to the max of both columns
If iRow <= LastRowA Then 'run only until max of column A
If ws.Cells(iRow, "A").Errors.Item(xlNumberAsText).Value = True Then
DataA(iRow, 1) = "N" & DataA(iRow, 1)
End If
End If
If iRow <= LastRowG Then 'run only until max of column G
If ws.Cells(iRow, "G").Errors.Item(xlNumberAsText).Value = True Then
DataG(iRow, 1) = "N" & DataG(iRow, 1)
End If
End If
Next iRow
'write array back to sheet
ws.Range("A1", "A" & LastRowA).Value = DataA
ws.Range("G1", "G" & LastRowG).Value = DataG
'read data into array
Dim DataO() As Variant 'read data from column O into array (max size = column A)
DataO = ws.Range("O1", "O" & LastRowA).Value
Dim DataS() As Variant 'read data from column G into array (max size = column G)
DataS = ws.Range("S1", "S" & LastRowG).Value
Dim oRow As Long, sRow As Long
oRow = 2 'output row start
sRow = 2
For iRow = 2 To Application.Max(LastRowA, LastRowG) 'combine loop to the max of both columns
If iRow <= LastRowA Then
If IsError(Application.Match(DataA(iRow, 1), DataG, 0)) Then
DataO(oRow, 1) = DataA(iRow, 1)
oRow = oRow + 1
End If
End If
If iRow <= LastRowG Then
If IsError(Application.Match(DataG(iRow, 1), DataA, 0)) Then
DataS(sRow, 1) = DataG(iRow, 1)
sRow = sRow + 1
End If
End If
Next iRow
'write array back to sheet
ws.Range("O1", "O" & LastRowA).Value = DataO
ws.Range("S1", "S" & LastRowG).Value = DataS
Application.ScreenUpdating = True
End Sub
New user here who is also very new to Excel VB.
At the moment, I have a macro which does what you see here.
Essentially, I have 2 columns which can sometimes have cells which contain vertically stacked lines of data in each cell. Each of those lines is split out and put into newly inserted rows below (one line of data in the cell per row).
The problem I am having now, is that while the new rows now contain data in the two columns which had to be split (34 and 35), the remaining cells are empty. I am having trouble bringing the remaining 38 columns down into the newly-created rows. You can see what I mean in the image I posted. Two new rows were created and I need to fill them with the content of row 1 (fill in to the shaded area).
Here is my code right now. The part that is commented out is me trying to fill the empty space. The un-commented code does what you see in the image.
Sub main()
Dim iRow As Long, nRows As Long, nData As Long
Dim IDVariables As Range
Dim arr As Variant
With Worksheets("UI").Columns("AH")
nRows = .Cells(.Rows.Count, 1).End(xlUp).Row
For iRow = nRows To 2 Step -1
With .Cells(iRow)
arr = Split(.Value, vbLf)
nData = UBound(arr) + 1
If nData > 1 Then
.EntireRow.Offset(1).Resize(nData - 1).Insert
.Resize(nData).Value = Application.Transpose(arr)
.Offset(, 1).Resize(nData).Value = Application.Transpose(Split(.Offset(, 1).Value, vbLf))
'Set IDVariables = Range("A" & iRow & ":AG" & iRow)
'IDVariables.Select
'Selection.Copy
'Range("A" & (iRow + 1) & ":A" & (iRow + nData -1)).Select
'Selection.Paste
End If
End With
Next iRow
End With
End Sub
Any help would be very much appreciated.
Thanks!
Tested and working fine....
Option Explicit
Sub ReCode()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1")
Dim LR As Long, i As Long, arr
LR = ws.Range("AH" & ws.Rows.Count).End(xlUp).Row
For i = LR To 2 Step -1
If InStr(ws.Range("AH" & i), vbLf) Then
ws.Range("A" & i + 1).EntireRow.Insert xlUp
ws.Range("A" & i).EntireRow.Copy ws.Range("A" & i + 1)
arr = Split(ws.Range("AH" & i), vbLf)
ws.Range("AH" & i) = arr(0)
ws.Range("AH" & i + 1) = arr(1)
arr = ""
End If
Next i
End Sub
I'm late doing this but I figured it out. I'll post my solution for anyone who has a similar problem.
Sub main()
Dim iRow As Long, nRows As Long, nData As Long
Dim arr As Variant
Dim IDVariables, Comments, AllocationCheck As Range
Application.ScreenUpdating = False
With Worksheets("PRM2_Computer").Columns("AH")
nRows = .Cells(.Rows.Count, 1).End(xlUp).Row
For iRow = nRows To 2 Step -1
With .Cells(iRow)
arr = Split(.Value, vbLf)
nData = UBound(arr) + 1
If nData = 1 Then
Range("AI" & iRow) = 1
Range("AK" & iRow) = "Single Industry"
End If
If nData > 1 Then
.EntireRow.Offset(1).Resize(nData - 1).Insert
.Resize(nData).Value = Application.Transpose(arr)
.Offset(, 1).Resize(nData).Value = Application.Transpose(Split(.Offset(, 1).Value, vbLf))
.Offset(, 2).Resize(nData).Value = Application.Transpose(Split(.Offset(, 2).Value, vbLf))
Set Comments = Range("AL" & iRow & ":AM" & iRow)
Comments.Copy Range("AL" & (iRow + 1) & ":AL" & (iRow + nData - 1))
Set AllocationCheck = Range("AK" & (iRow) & ":AK" & (iRow + nData - 1))
AllocationCheck.Value = Application.Sum(Range("AI" & iRow & ":AI" & (iRow + nData - 1)))
Set IDVariables = Range("A" & iRow & ":AG" & iRow)
IDVariables.Copy Range("A" & (iRow + 1) & ":A" & (iRow + nData - 1))
End If
End With
Next iRow
End With
End Sub
I have data for the year 2019 to 2021 and from 2016 to 2018. I want to combine the data and the KeyNumbers to follow, i was thinking it is best via VBA. But i am clueless on how to do it, so far i move the data from one sheet to this one, and here i have the data collected. But the years is seperated. I need it to be as shown from row R to T. This would be a big help for me, because i have 65 of these sheets. So a simple VBA would be so much help!
Thanks in advance
I tried to write VBA. It is getting there but mixing it up as result
Sub x()
Dim lngDataColumns As Long
Dim lngDataRows As Long
lngDataColumns = 2
lngDataRows = 20
For t = 1 To lngDataRows
Range("n2").Offset(((t - 1) * lngDataColumns) - 1, 0).Resize(lngDataColumns, 1).Value = _
Application.Transpose(Range("g24:h24").Offset(t).Value)
Range("o2").Offset(((t - 1) * lngDataColumns) - 1, 0).Resize(lngDataColumns, 1).Value = _
Application.Transpose(Range("i24:j24").Offset(t).Value)
Next t
End Sub
Sub y()
Dim lngDataColumns As Long
Dim lngDataRows As Long
lngDataColumns = 3
lngDataRows = 20
Range("p2").Offset(((t - 1) * lngDataColumns) - 1, 0).Resize(lngDataColumns, 1).Value = _
Application.Transpose(Range("h5").Offset(t).Value)
End Sub
You could try:
Option Explicit
Sub test()
Dim LastrowH As Long, Year As Long, i As Long, LastrowR As Long
Dim Amount As Double
Dim Key As String
With ThisWorkbook.Worksheets("Sheet1")
LastrowH = .Cells(.Rows.Count, "H").End(xlUp).Row
For i = 2 To LastrowH
'Check if Key start from DR (we assume that anything start with DR is key we need)
If Left(.Range("H" & i).Value, 2) = "DR" Then 'Remove this line
Key = .Range("H" & i).Value
Amount = .Range("L" & i).Value
Year = .Range("M" & i).Value
LastrowR = .Cells(.Rows.Count, "R").End(xlUp).Row
.Range("R" & LastrowR + 1).Value = Key
.Range("S" & LastrowR + 1).Value = Amount
.Range("T" & LastrowR + 1).Value = Year
If Year = 2018 Then
.Range("R" & LastrowR + 2 & ":R" & LastrowR + 4).Value = Key
.Range("S" & LastrowR + 2 & ":S" & LastrowR + 4).Value = Amount
.Range("T" & LastrowR + 2).Value = Year + 1
.Range("T" & LastrowR + 3).Value = Year + 2
.Range("T" & LastrowR + 4).Value = Year + 3
End If
End If 'Remove this line
Next i
End With
End Sub
if you want to remove the DR ( if statement) remove the lines with 'Remove this line at the end.
I have multiple rows which are sometimes in order and sometimes not.
Out of rows which are in order, I would need to create a range, which are not in order just to copy the number.
The thing is, the most rows in order can be even 20.
For example cells:
1
3
5
6
7
8
9
10
13
14
15
There would be:
1
3
5-10
13-15
Is it possible to code it?
Thanks
Assuming your data starts with A1.... and
required results will be printed at C column.
Try with below code
Sub test()
Dim i As Long, lastrow As Long, incre As Long
Dim startno As Variant
Dim endno As Variant
incre = 1
lastrow = Range("A" & Rows.Count).End(xlUp).Row
For i = 1 To lastrow
If Cells(i, 1) = (Cells(i + 1, 1) - 1) Then
startno = Cells(i, 1)
Do While Cells(i, 1) = (Cells(i + 1, 1) - 1)
endno = Cells(i + 1, 1)
i = i + 1
Loop
Cells(incre, 3) = "'" & startno & "-" & endno
incre = incre + 1
Else
Cells(incre, 3) = Cells(i, 1)
incre = incre + 1
End If
Next i
End Sub
if you want the address of all consecutive ranges you could use:
Option Explicit
Sub main()
Dim rangeStrng As String
With Worksheets("MyRowsSheet") '<--| change "MyRowsSheet" with your actual sheet name
rangeStrng = .Range("A1", .Cells(.Rows.Count, "A").End(xlUp)).SpecialCells(xlCellTypeConstants).Areas.Parent.Address(False, False)
End With
End Sub
if you want only the rows range then you could use:
Option Explicit
Sub main2()
Dim rng As Range
Dim rowsRangeStrng As String
With Worksheets("MyRowsSheet") '<--| change "MyRowsSheet" with your actual sheet name
For Each rng In .Range("A1", .Cells(.Rows.Count, "A").End(xlUp)).SpecialCells(xlCellTypeConstants).Areas
If rng.Rows.Count = 1 Then
rowsRangeStrng = rowsRangeStrng & rng.Rows(1).Row & ","
Else
rowsRangeStrng = rowsRangeStrng & rng.Rows(1).Row & "-" & rng.Rows(rng.Rows.Count).Row & ","
End If
Next rng
End With
If rowsRangeStrng <> "" Then rowsRangeStrng = Left(rowsRangeStrng, Len(rowsRangeStrng) - 1)
End Sub
If I understood your question correctly, you are not looking to address a range, but rather want an output table. This code below should provide you with just that. My input numbers are in column A, and the output is in column B.
Sub sequentials()
Dim tws As Worksheet
Dim tmpRowA, tmpRowB As Integer
Dim seq() As Long
Dim frA, frB, lrA As Integer 'firstrow col A, col B, lastrow of data
Set tws = ThisWorkbook.Worksheets("Sheet1")
frA = 2
frB = 2
lrA = tws.Range("A1000000").End(xlUp).Row
'Input in column A, Output in column B
'Headers in Row 1
ReDim seq(0 To lrA - 1)
seq(0) = -2
seq(1) = tws.Range("A" & frA).Value
tmpRowA = frA
tmpRowB = frB
tws.Range("B" & frB & ":B" & lrA).NumberFormat = "#"
For r = frA + 1 To lrA
If r = 23 Then
r = 23
End If
With tws
seq(r - 1) = .Range("A" & r).Value
If seq(r - 1) = seq(r - 2) + 1 Then
If r = lrA Then
.Range("B" & tmpRowB).Value = .Range("A" & tmpRowA - 1).Value & "-" & seq(r - 1)
End If
Else
If seq(r - 2) = seq(r - 3) + 1 Then
.Range("B" & tmpRowB).Value = .Range("A" & tmpRowA - 1).Value & "-" & seq(r - 2)
Else
.Range("B" & tmpRowB).Value = seq(r - 2)
End If
tmpRowB = tmpRowB + 1
tmpRowA = r + 1
If r = lrA Then
.Range("B" & tmpRowB).Value = seq(r - 1)
End If
End If
End With
Next r
End Sub
Proof of concept: