I'm trying to optimize code that will delete rows that meet certain criteria. I have working code, but the following code creates 7 seconds of wait time to execute:
Dim j As Long
For j = 2 To Rows.Count
If (Range("J" & j).Value <> "") Then
Range("A" & j & ":R" & j).Select
Selection.Delete Shift:=xlUp
End If
Next j
The following code runs instantly; however, I can't get it to work once j = 2. What code needs to be added to stop the loop before it deletes the column headers in row 1?
' Delete rows where column J is not blank
For j = Range("J" & Rows.Count).End(xlUp).Row To 1 Step -1
If (Range("J" & j).Value <> "") Then
Range("A" & j & ":R" & j).Select
Selection.Delete Shift:=xlUp
End If
Next j
As mentioned in the comments, you should looking backward for deletions. If you do the deletions from row#2 to the last row, there might be some rows should be deleted but remained there. Take this for example, assuming we are going to delete row#3 and row#4. If we do it forward, the row#4 becomes to new row#3 after deleting old row#3. And the next row to be checked is row#4, that is the original row#5. So the data in row#4 is actually in row#3 now and it'll never be deleted.
However, when your data is quite massive, the deletions would take so many resource that it drags down the speed. It would be better to find all the ranges to be deleted and delete them at once in the end. We can do it by Union method. And this can also prevent the problem mentioned before, so we can do it forward as other loops.
Lastly, you can avoid selecting ranges since it is not so efficient. Range().Delete can simply delete the range and without selecting it.
The code would be like this.
'pseudo code
Sub deletion()
For i = 2 To lastrow
If shouldBeDeleted Then
If deletingRng Is Nothing Then
Set deletingRng = Cells(i, X)
Else
Set deletingRng = Union(deletingRng, Cells(i, X)
End If
End If
Next i
deletingRng.Delete Shift:=xlUp
End Sub
Related
I have a file that has a bunch of Cells in the A column (1500) that look like this:
Perfect Imperfection;"Kevin Gates";"Luca Brasi 2: Gangsta Grillz";1
or
Perfect Imperfection;"Kevin Gates";"Luca Brasi 2: Gangsta Grillz";0
I am trying to delete cells that end in ;1
Note that some song titles have a 1 in them, and others take the form of:
Perfect Imperfection;;;1
I'm using the following code from a different Stack Overflow post that I have edited slightly:
Sub DeleteRowsWithX()
maxRow = ActiveSheet.UsedRange.Rows.Count
MsgBox (maxRow)
For i = 1 To maxRow
Do While (StrComp(ActiveSheet.Cells(i, 1).Text, ";1", vbTextCompare) = 0)
Rows(i).Select
Selection.Delete Shift:=xlUp
MsgBox ("Deleted")
Loop
Next
End Sub
If it helps, here are some examples of the file:
Perfect Imperfection;"Kevin Gates";"Luca Brasi 2: Gangsta Grillz";1
Perfect Strangers;"Lil Wayne";"Tha Carter V";1
Perplexing Pegasus;"Rae Sremmurd";;1
Phone Numbers Wiz Khalifa;;;0
Piano Man;"Billy Joel";;1
Picasso Baby Jay Z;;;0
Pick Up the Phone ft Young Thug Travis Scott;;;0
Picture;"Kid Rock";;1
Pillowtalk Conor Maynard;;;1
Pimp Juice;Nelly;Nellyville;1
Pinball Wizard;"The Who";;1
Pink Toes Childish Gambino;;;1
Which should look like:
Phone Numbers Wiz Khalifa;;;0
Picasso Baby Jay Z;;;0
Pick Up the Phone ft Young Thug Travis Scott;;;0
However, nothing is deleting. Can anybody advise? NOTE -- this not need to be done in VBA, I just want to delete rows that end in 1
Requirements: Delete entire row of values in column 1 that end with ";1"
For this kind of requirements suggest the use of AutoFilter and SpecialCells to delete all the target rows at once.
Try this:
Sub AutoFilter_To_DeleteRows()
With ActiveSheet
Application.Goto .Cells(1), 1
Rem Add a temporary header to avoid indiscriminate deletion of the first row.
.Cells(1).EntireRow.Insert
.Cells(1).Value2 = "Temporary Header"
Rem Filter values ending with ";1"
.Columns(1).AutoFilter Field:=1, Criteria1:="=*;1"
Rem Delete all resulting rows
.Columns(1).SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With
End Sub
Keeping the answer close to the code that you have written.
You need to loop from the bottom of your list to the top. That way when rows are deleted, you do not skip rows. This can be done in your For loop by starting with the bottom of the list and moving backwards to the first row using Step -1.
The Right function can be used to test the last two characters of the cell value to see if they match to ;1.
The Do While can be removed.
The MsgBox's have been expanded to provide more detail when testing. They can be commented out once you are happy with the way the code is running.
Sub DeleteRowsWithX()
maxRow = ActiveSheet.UsedRange.Rows.Count
MsgBox "No. of Rows: " & maxRow
For i = maxRow To 1 Step -1
ValOfCell = ActiveSheet.Cells(i, 1).Value2
If Right(ValOfCell, 2) = ";1" Then
Rows(i).Delete Shift:=xlUp
MsgBox "Row: " & i & vbCrLf & "Value: " & ValOfCell & vbCrLf & "has been deleted."
End If
Next
End Sub
Jerry, I could not get StrComp to work the way I wanted, so I used Mid & Len to accomplish what you need. This will work since all the song titles end with ";?". Also, I did not add to the code, but consider doing everything you can to not use the Select method - this can lead to complications.
Sub DeleteRowsWithX()
Dim maxrow As Integer
Dim i As Integer
maxrow = ActiveSheet.UsedRange.Rows.Count
For i = 1 To maxrow
Do While Mid(Cells(i, 1).Text, Len(Cells(i, 1).Text) - 1, 2) = ";1"
Rows(i).Select
Selection.Delete Shift:=xlUp
MsgBox ("Deleted")
Loop
Next
End Sub
I got it working just fine, but it is painfully slow. The first function that renames some cells runs really quick, but the while loop that deletes certain merged cell rows takes over a minute for multiple sheets.
Here is the relevant code:
Dim i As Long
Dim LastRow As Long
LastRow = Cells(Rows.Count, rowtofilter).End(xlUp).Row
'Search for merged cells and not "string1" in column2 and not "string2" in column4, replace text
For i = rowtofilter To LastRow
If Range(ColumnLetter1 & i).MergeArea.Cells.Count > 1 And Range(ColumnLetter2 & i) <> "string1" And Range(ColumnLetter4 & i) <> "string2" Then
Range(ColumnLetter3 & i).Value = "Merged Cells"
End If
Next i
'Search for merged cells and not "string1" in column2 and not "string2" in column4, delete rows
i = LastRow - rowtofilter
Do While i > (rowtofilter - 1)
If Range(ColumnLetter1 & i).Value = 0 And Range(ColumnLetter2 & i) <> "string1" And Range(ColumnLetter4 & i) <> "string2" Then
Range(ColumnLetter1 & i).EntireRow.Delete
End If
i = i - 1
Loop
If you haven't yet, add application.screenupdating=false at the beginning and application.screenupdating=true at the end of your code to speed things up.
Then, if still slow, do the deletion all at once:
Dim rgToDelete As Range
i = LastRow - rowtofilter
Do While i > (rowtofilter - 1)
If Range(ColumnLetter1 & i).Value = 0 And Range(ColumnLetter2 & i) <> "string1" And Range(ColumnLetter4 & i) <> "string2" Then
If rgToDelete Is Nothing Then
Set rgToDelete = Range(ColumnLetter1 & i)
Else
Set rgToDelete = Union(rgToDelete , Range(ColumnLetter1 & i))
End If
End If
i = i - 1
Loop
rgToDelete .EntireRow.Delete
Instead of using Rows.Count, only work with the UsedRange. Worksheet.UsedRange.Rows.Count
Hide the sheet while doing the second bit. Excel wants to update the screen with every deleted row. By hiding the sheet, you stop that nonsense. Worksheet.Visible = xlSheetVeryHidden
If there are calculations based on the rows being deleted, turn off automatic calculations while doing the delete. In fact, you might just do it anyway. This will prevent Excel from recalculating the sheet on every delete. Application.Calculation = xlCalculationManual
Remember to turn everything back on when you're done.
*Note that, in the above examples, Worksheet should be replaced by a reference to whatever worksheet you are using.
I want to perform a goal seek for several rows (I don't know exactly how many - in the code I have below it stops in row 100). The thing is, for example, if I have 10 rows, row number 5 can be empty. So I want it to skip from row 4 to row 6, then continue, then "jump" another empty row if they exist.
I want to set cell M2 to 0 by changing the value of cell K2. The same for row 3, row 4, etc. and I want it to skip empty rows.
Right now I just have this... a simple case
Sub GSeek()
Dim i As Long
For i = 2 To 100
range("M" & i).GoalSeek Goal:=0, ChangingCell:=range("K" & i)
Next
End Sub
Try this
Dim i As Long
For i = 2 To 100
If range("M" & i).Value <> "" Then
range("M" & i).GoalSeek Goal:=0, ChangingCell:=range("K" & i)
End If
Next i
Each time it just makes sure that the cell isn't empty. If it is, it'll just move to next i
I cannt understand, why my excel script does not work anymore..
I need to do simple copy Paste function,
First, I have 1 value (Mean) which is generated and it changes randomly after any action (Very important point!)
So , I need a kind of "simulation", means to copy the value and put it in another worksheet, after that the excel is refreshing automatically and I get a new mean-value..
This process should be repeated 1000 times. It means i will have 1000 different values at the end, because of random changes of my mean-value
I have a script, which works perfect for this purpose.
Dim i As Integer
Sheets("Worksheet2").Select
Cells(4, 23).Select
Selection.Copy
'
Sheets("Worksheet3").Select
For i = 1 To 1000
Cells(1 + i, 1).PasteSpecial Paste:=xlPasteValues
Next i
'
End Sub
Now,
I have not only one cell (my mean-value) but two! ( median from the same data)
It means, now it should copy two cells simultaneously (range) and paste than in the new worksheet, in the new range.
So, it is the same process, like in my script, but with two cells
a kind of this..
Dim i As Integer
Sheets("Fracht Modell Roh").Select
Range("W4:X4").Select
Selection.Copy
'
Sheets("Ergebnisse").Select
For i = 1 To 100
Range("A2:B2" & 1 + i).PasteSpecial Paste:=xlPasteValues
Application.CalculateFull
Next i
'
End Sub
I tried to do it with range() BUT!!! it doesnt refresh my mean and median values anymore ... or something else... so I get 1000 times the SAME!! value after the script running.
I can not understand, what is his problem. Why in first case it works perfect, and if I do the same task with range, it seems to copy the same value about 1000 times, but not refreshing or changing it.
pleas, I hope, anybody could help me
thank you very much!
I think you meant to write this:
Dim i As Integer
Sheets("Fracht Modell Roh").Select
Range("W4:X4").Select
Selection.Copy
'
Sheets("Ergebnisse").Select
For i = 1 To 1000
Range("A" & i + 1 & ":B" & i + 1).PasteSpecial Paste:=xlPasteValues
Next i
However, your code doesn't need the Select statement to work, that will just let the code jump through sheets over and over without reasons. I might rather write it like this:
Dim i As Integer
Sheets("Fracht Modell Roh").Range("W4:X4").Copy
'
With Sheets("Ergebnisse")
For i = 1 To 1000
.Range("A" & i + 1 & ":B" & i + 1).PasteSpecial Paste:=xlPasteValues
Next i
End With
Same thing for your other code snippet, the one for a single random value:
Dim i As Integer
Sheets("Worksheet2").Cells(4, 23).Copy
'
With Sheets("Worksheet3")
For i = 1 To 1000
.Cells(1 + i, 1).PasteSpecial Paste:=xlPasteValues
Next i
End With
Moreover, if as I imagine the two cells in the first sheet contains two random functions =RAND(), why you don't directly write them in VBA?
With Sheets("Ergebnisse")
For i = 1 To 1000
.Range("A" & i + 1).Value = Rnd
.Range("B" & i + 1).Value = Rnd
Next i
End With
We have a blank workbook which I would like the user to be able to paste a list of reference numbers into column A. Some of these reference numbers will have a "+" at the end.
Sub texter1()
With Sheets("texter")
ll = .UsedRange.SpecialCells(xlCellTypeLastCell).Row
For i = 1 To ll
If InStr(1, .Range("a" & i).Value, "+", 1) Then
.Range("b" & i).Formula = "=LEFT(A" & i & ", LEN(A" & i & ")-1)"
.Range("c" & i).Value = Sheets("texter").Range("b" & i).Value
.Range("d" & i).Formula = "=VLOOKUP($c" & i & ", _
[Current_Master.xlsm]Master!$A$3:$BB$20000,14,FALSE)"
.Range("e" & i).Formula = "=VLOOKUP($c" & i & ", _
[Current_Master.xlsm]Master!$A$3:$BB$20000,15,FALSE)"
Else
Cells(i, "a").EntireRow.Delete
End If
Next i
End With
End Sub
I would like reference numbers without the "+" to have the whole row deleted. Reference numbers with a "+" work fine.
this seems to work but has to be run multiple times for it to delete all the rows without a "+" and I cannot figure out why. Please help
Thank you
You cannot delete a row inside a loop as far as affects the iterations. Imagine this: you have 4 rows; the second row meets the conditions and is deleted; in the next iteration the counter is 3 but the row number 3 is now the fourth row (when you delete a row, all the ones below go up one position); consequently, row number 3 wouldn't be analysed. Thus the solution is simple:
Cells(i, "a").EntireRow.Clear()
If you want to actually delete the whole row, you would have to do it outside the main loop. For example: store all the rows to be deleted in an array and iterate through this array right after completing the main loop.
Another alternative would be performing the iterations in the main loop in inverse order (from maximum row to minimum one), although this option is not always applicable (not sure if in your case) and might provoke further problems. The two options above are good enough, I have mentioned this last alternative just as something worthy to be known.
--- UPDATE
To delete the rows after the main loop you can use something on these lines:
'Declaration of variables
ReDim allRows(ll + 1) As Long
Dim allRowsCount As Long: allRowsCount = 0
In your main loop you store the given rows (where you have now Cells(i, "a").EntireRow.Delete):
For i = 1 To ll
'etc.
else
allRowsCount = allRowsCount + 1
allRows(allRowsCount) = i
After the loop is completed, you go through all the stored rows (in inverse order) and delete them:
If (allRowsCount > 0) Then
Dim curRow As Long: curRow = allRowsCount + 1
Do
curRow = curRow - 1
.Rows(allRows(curRow)).Delete
Loop While (curRow > 1)
End If
End With
End Sub