Delete entire row based on row number VBA - excel

I have a list of 18,806 rows (worksheet named "Reference") that need to be deleted from a 90,000+ row excel sheet (worksheet named "To Delete"). I'm trying to create an array containing the row numbers in "Reference", iterate through the array, and delete each row in the array from "To Delete". So far I have:
Sub deleteRows()
Dim rowArray As Variant
ReDim rowArray(18085) As Integer
rowArray = Sheets("Reference").Range("A1:A18086").Value
Dim Arr As Variant
Dim del As Integer
Dim i As Integer
i = 1
For Each Arr In rowArray
del = Arr
Sheets("To Delete").Cells(del, 1).EntireRow.Clear
Next
End Sub
Edit: Figured it out! It just clears contents and has some memory overflow errors but I'm working around that. Just wanted to post here for future reference :)

Based on my previous comment, I offer a suggestion to not shift your row numbers:
For Each a In rowArray
del = rowArray(a)
Worksheets.Rows(del).ClearContents
Next a
Dim rowNum as Integer
rowNum = Worksheets.Rows.RowCount
While rowNum > 0
If Worksheets.Cells(rowNum,1).Value = "" Then
Worksheets.Rows(rowNum).Delete
End If
rowNum = rowNum - 1
Loop
Here is the code after the workup. This should be almost to the point of being usable:
Sub deleteRows()
Dim rowArray(18086) As Integer
Dim i As Integer, j As Integer, del As Integer, rowNum As Integer
i = 1
j = 18086
While i <= j
rowArray(i) = Sheets("Reference").Range(i, 1).Value
i = i + 1
Loop
For Each a In rowArray
del = rowArray(a)
Sheets("Reference").Rows(del).ClearContents
Next a
rowNum = Sheets("Reference").Rows.RowCount
While rowNum > 0
If Sheets("Reference").Cells(rowNum, 1).Value = "" Then
Sheets("Reference").Rows(rowNum).Delete
End If
rowNum = rowNum - 1
Loop
End Sub
Make sure you are defining your variables before you call them, for safety. This is a universal rule in code.

Try this:
Worksheets.Rows(i).Delete
With i as your row number.
Nb: It will cause a shit into your rows number

Related

how to change column after n rows while inserting values from array to excel cell VBA

can you please guide how to put array values in multiple columns like first four values in first column , than 5 values in second column, and than may be 2 in second column….. and so on. i tried do while loop and for loop but the results are not satisfactory ————————-
Sub PickNamesAtRandom()
Dim HowMany As Long
Dim NoOfNames As Long
Dim RandomColumn As Integer
Dim RandomRow As Integer
Dim Names() As String ‘Array to store randomly selected names
Dim i As Byte
Dim CellsOutRow As Integer
Dim CellsOutColumn As Integer ‘Variable to be used when entering names onto worksheet
Dim ArI As Byte ‘Variable to increment through array indexes
Application.ScreenUpdating = False
HowMany = WorksheetFunction.Sum(Sheets(“test”).Range(“A2:E2”))
CellsOutRow = 3
CellsOutColumn = 1
ReDim Names(1 To HowMany) ‘Set the array size to how many names required
NoOfNames = Application.CountA(Sheets(“sheet1”).Range(“D4:L45”)) ‘ Find how many names in the list
i = 1
Do While i <= HowMany
RandomNo:
RandomRow = Application.RandBetween(1, 45)
RandomColumn = Application.RandBetween(1, 15)
'Check to see if the name has already been picked
For ArI = LBound(Names) To UBound(Names)
If Names(ArI) = Sheets("sheet1").Cells(RandomRow, RandomColumn).Value Then
GoTo RandomNo
End If
Next ArI
Names(i) = Sheets("sheet1").Cells(RandomRow, RandomColumn).Value ' Assign random name to the array
i = i + 1
Loop
Dim RequiredRows As Integer
RequiredRow = 2
'Loop through the array and enter names onto the worksheet
For ArI = LBound(Names) To UBound(Names)
Do
Cells(CellsOutRow, CellsOutColumn) = Names(ArI)
CellsOutRow = CellsOutRow + 1
Loop While CellsOutRow < Cells(RequiredRow, CellsOutColumn).Value
CellsOutColumn = CellsOutColumn + 1
Next ArI
Application.ScreenUpdating = True
End Sub
Option Explicit
Sub WriteValues(ByVal values As Collection)
Dim row As Long
Dim col As Long
Dim val As Variant
row = 1
For Each val In values
Select Case row
' first four values in first column
Case Is <= 4
col = 1
' than 5 values in second column,
Case Is <= 9
col = 2
' and than may be 2 in second column...
Case Is <= 11
col = 2
' row > 11
Case Else
col = 3
End Select
Cells(row, col).Value = val
row = row + 1
Next val
End Sub

VBA Multi-Criteria Parent-Child SumProduct

Please help.
I'm trying to create a user defined function that will use an array as multiple criteria (Pedigree) to check for corresponding parents (Parent) and then sum their respective ranges (Sumrange).
I've managed to create code that will check if a parent is in the pedigree range which will then return a result of 1 or 0. This will not return true values if blanks verify blanks. I intend to create an array with these 1's and 0's to then SumProduct it with my Sumrange. My problem is that I am unable create an array of these 1's and 0's and SumProduct them with the Sumrange without returning a #value.
This below code doesn't include the SumProduct portion but just returns 1 or 0 based on the criteria.
Function ProdIfs(Parent As Range, Pedigree As Range, Sumrange As Range) As Long
Application.Volatile
Dim i As Variant
Dim j As Variant
Dim result As Integer
result = 0
For Each i In Parent
For Each j In Pedigree
If i.Value = "" Or j.Value = "" Then
result = result
ElseIf i.Value = j.Value Then
result = 1: GoTo NextIteration
End If
Next j
NextIteration:
Next i
ProdIf = result
End Function
Thanks for you help.
Thanks to Super Symmetry for getting this 99% of the way there.
Since the original code returned a 1 or 0, I changed the code to provide a sumproduct.
Also I've made the PedigreeRange loop through columns instead of rows to fit the way my Pedigree data is.
Function ProdIfs(Parent As Range, Pedigree As Range, Sumrange As Range) As Variant
Application.Volatile
Dim i As Long
Dim j As Long
Dim result() As Variant
ReDim result(1, 1 To Parent.Rows.Count)
Dim x As Long
For i = 1 To Parent.Rows.Count
x = 0
result(1, i) = x
For j = 1 To Pedigree.Columns.Count
If Parent.Cells(i, 1).Value <> "" And Pedigree.Cells(1, j) <> "" And Parent.Cells(i, 1) = Pedigree.Cells(1, j) Then
x = 1
Exit For
End If
Next j
result(1, i) = x * Sumrange(i, 1).Value
Next i
ProdIfs = WorksheetFunction.Sum(result)
End Function
Thanks again. If there are any improvements that can be made to this please let me know.
Answer changed following comments
If you want to return an array, you actually have to create and populate an array in your function and make sure the return type is Variant.
Try this
Function ProdIfs(Parent As Range, Pedigree As Range, Sumrange As Range) As Variant
Application.Volatile
Dim i As Long
Dim j As Long
Dim result() As Integer ' The return value must be an array
ReDim result(1 To Parent.Rows.Count, 1 To 1) ' Assuming Parent is 1 column
For i = 1 To Parent.Rows.Count
result(i, 1) = 0 ' set to 0 by default but always good to do it explicitly
For j = 1 To Pedigree.Rows.Count
If Parent.Cells(i, 1).Value <> "" And Parent.Cells(i, 1) = Pedigree.Cells(j, 1) Then
result(i, 1) = 1
Exit For
End If
Next j
Next i
ProdIfs = result
End Function
Edit: following your answer
You just need to keep a running sum.
To make your code run faster you should read values of these ranges and process them in memory. (It is much faster than asking excel for values in cells).
The return value should be a Double
This feels like a SumIfs ranther than a ProdIfs
Function ProdIfs(Parent As Range, Pedigree As Range, Sumrange As Range) As Double
Application.Volatile
Dim i As Long
Dim v As Variant
Dim vParent As Variant: vParent = Parent.Value
Dim vPedigree As Variant: vPedigree = Pedigree.Value
Dim vSumRange As Variant: vSumRange = Sumrange.Value
ProdIfs = 0
For i = 1 To UBound(vParent, 1)
For Each v In vPedigree
If len(v) > 0 And v = vParent(i, 1) Then
ProdIfs = ProdIfs + vSumRange(i, 1)
Exit For
End If
Next v
Next i
End Function

How to sort an array to a Range

I have an array of numbers in an excel spreadsheet which I am trying to sort (all numbers >60) using a user defined vba function and i want to return the result as a range in the same excel sheet.
I am getting a value error when i run this function in excel.I am not too sure where this error is coming from as I a new to VBA.I would really appreciate some guidance in resolving this issue.
Array Excel
Column A
200
50
23
789
Function trial(number As Range)
Dim cell As Range
Dim savearray() As Variant
Dim d As Long
For Each cell In Range("a3:a6").Cells
If cell.Value > 60 Then
d = d + 1
ReDim Preserve savearray(1 To d)
savearray(1, d) = cell.Value
trial = savearray
End If
Next cell
End Function
There is a bit of work to do on your Sub. However, to help you, below is a way to dynamically build an array:
d = 0
For Each cell In Range("A3:A1000")
If cell.Value > 60 Then
If d = 0 Then
ReDim savearray(0 To 0)
Else
ReDim Preserve savearray(0 To UBound(savearray) + 1)
End If
savearray(d) = cell.Value
d = d + 1
End If
Next cell
I feel like you might want to rather return a sorted array and only then, cast results to a Range
First we create a Function to sort our array
Private Function BubbleSort(ByRef from() As Variant) As Variant()
Dim i As Integer, j As Integer
Dim temp As Variant
For i = LBound(from) To UBound(from) - 1
For j = i + 1 To UBound(from)
If from(i) < from(j) Then
temp = from(j)
from(j) = from(i)
from(i) = temp
End If
Next j
Next i
BubbleSort = from ' returns sorted array
End Function
Then we create a simple "Range replacer" procedure
Private Sub replace_with_sorted(ByVal which As Range)
Dim arr() As Variant
arr = Application.Transpose(which)
arr = BubbleSort(arr)
which = Application.Transpose(arr)
End Sub
So the invokation would look the following way:
Private Sub test()
replace_with_sorted Range("A1:A4")
End Sub
This of course produces the expected result:
EDIT: Just noticed you want to sort only values larger than 60.
In that case, simply fill an array with values larger than 60 and use the same application.
Private Sub test()
Dim arr() as Variant: arr = Application.Transpose(Range("A1:A4"))
Dim above60() as Variant
Dim i as Integer, j as Integer: j = 0
For i = LBound(arr) To UBound(arr)
If arr(i) > 60 Then
ReDim Preserve above60(j)
above60(j) = arr(i)
j = j + 1
End If
Next i
ReDim arr()
arr = BubbleSort(above60)
' returns sorted array, do whatever u want with it _
(place it in whatever range u want, not defined in ur question)
End Sub

Loop through column, store values in an array

I am trying to find a way to:
Loop through a column (B column)
Take the values, store them in an array
Loop through that array and do some text manipulation
However, I cannot think of a way to loop through a column and take those values, storing them in an array. I have looked through Stack Overflow and google but have not found a successful solution.
In advance, thank you for your help.
Sub collectNums()
Dim eNumStorage() As String ' initial storage array to take values
Dim i as Integer
Dim j as Integer
Dim lrow As Integer
lrow = Cells(Rows.Count, "B").End(xlUp).Row ' The amount of stuff in the column
For i = lrow To 2 Step -1
If (Not IsEmpty(Cells(i, 2).Value)) Then ' checks to make sure the value isn't empty
i = eNumStorage ' I know this isn't right
Next i
If (IsEmpty(eNumStorage)) Then
MsgBox ("You did not enter an employee number for which to query our database. Quitting")
Exit Sub
End If
End Sub
This is the easiest way to get column to array:
Public Sub TestMe()
Dim myArray As Variant
Dim cnt As Long
myArray = Application.Transpose(Range("B1:B10"))
For cnt = LBound(myArray) To UBound(myArray)
myArray(cnt) = myArray(cnt) & "something"
Next cnt
For cnt = LBound(myArray) To UBound(myArray)
Debug.Print myArray(cnt)
Next cnt
End Sub
It takes the values from B1 to B10 in array and it gives possibility to add "something" to this array.
The Transpose() function takes the single column range and stores it as an array with one dimension. If the array was on a single row, then you would have needed a double transpose, to make it a single dimension array:
With Application
myArray = .Transpose(.Transpose(Range("A1:K1")))
End With
MSDN Transpose
CPearson Range To Array
Creating an Array from a Range in VBA
Just adding a variation on Vityata's which is the simplest way. This method will only add non-blank values to your array. When using your method you must declare the size of the array using Redim.
Sub collectNums()
Dim eNumStorage() As String ' initial storage array to take values
Dim i As Long
Dim j As Long
Dim lrow As Long
lrow = Cells(Rows.Count, "B").End(xlUp).Row ' The amount of stuff in the column
ReDim eNumStorage(1 To lrow - 1)
For i = lrow To 2 Step -1
If (Not IsEmpty(Cells(i, 2).Value)) Then ' checks to make sure the value isn't empty
j = j + 1
eNumStorage(j) = Cells(i, 2).Value
End If
Next i
ReDim Preserve eNumStorage(1 To j)
'Not sure what this bit is doing so have left as is
If (IsEmpty(eNumStorage)) Then
MsgBox ("You did not enter an employee number for which to query our database. Quitting")
Exit Sub
End If
For j = LBound(eNumStorage) To UBound(eNumStorage) ' loop through the previous array
eNumStorage(j) = Replace(eNumStorage(j), " ", "")
eNumStorage(j) = Replace(eNumStorage(j), ",", "")
Next j
End Sub

Split data string over columns AND rows using VBA

I am trying to speed up a currently working automated workbook.
PHP sends a string similar to the below to VBA:
1[|:#:|]text-one[|:#:|]code-one[|:#:|]qty-one[{:#:}]
2[|:#:|]text-two[|:#:|]code-two[|:#:|]qty-two[{:#:}]
where
[|:#|] represents "new column"
[{:#:}] represents "new row"
When it is parsed by the VBA this is the output:
I currently use the following VBA code to parse this into a workbook:
myArray = Split(myReply, "[{:#:}]")
myRow = 1
For Each element In myArray
myRow = myRow + 1
subArray = Split(element, "[|:#:|]")
myCol = 2
For Each subelement In subArray
myCol = myCol + 1
Cells(myRow, myCol).Value = subelement
Next subelement
Next element
I am about to start optimising the code in this workbook and I am aware I can do something like (pseudo code):
for each element....
Range("C2:F2").Value = Split(element, "[|:#:|]") 'Example row number would be incremental
However is there a way to do it so that I can split into the entire Range?
For example, If I know there are 29 "rows" within the data that has been returned, I would like to be able to use split to place the data into all the rows.
I imagine the syntax would be something similar to the below, however this doesn't seem to work:
Range("C2:F29").Value = Split(Split(element, "[|:#:|]"),"[{:#:}]")
The optimal thing to do is to do everything in native VBA code and not interact with the Excel sheet until the end. Writing to sheet is a time consuming operation, so this procedure does it once and once only, writing the whole two-dimensional array at once, rather than writing it line by line. Therefore no need to disable screen updating, calculation, or anything else.
Function phpStringTo2DArray(ByVal phpString As String) As Variant
Dim iRow As Long
Dim iCol As Long
Dim nCol As Long
Dim nRow As Long
Dim nColMax As Long
Dim lines() As String
Dim splitLines() As Variant
Dim elements() As String
lines = Split(phpString, "[{:#:}]")
nRow = UBound(lines) - LBound(lines) + 1
ReDim splitLines(1 To nRow)
For iRow = 1 To nRow
splitLines(iRow) = Split(lines(iRow - 1), "[|:#:|]")
nCol = UBound(splitLines(iRow)) - LBound(splitLines(iRow)) + 1
' in case rows have different number of columns:
If nCol > nColMax Then nColMax = nCol
Next iRow
Erase lines
'We now have a (Variant) array of arrays. Convert this to a regular 2D array.
ReDim elements(1 To nRow, 1 To nColMax)
For iRow = 1 To nRow
nCol = UBound(splitLines(iRow)) - LBound(splitLines(iRow)) + 1
For iCol = 1 To nCol
elements(iRow, iCol) = splitLines(iRow)(iCol - 1)
Next iCol
Next iRow
Erase splitLines
phpStringTo2DArray = elements
End Function
Example usage:
Dim s As String
Dim v As Variant
s = "1[|:#:|]text-one[|:#:|]code-one[|:#:|]qty-one[{:#:}]2[|:#:|]text-two[|:#:|]code-two[|:#:|]qty-two[{:#:}]"
v = phpStringTo2DArray(s)
'Write to sheet
Range("A1").Resize(UBound(v, 1), UBound(v, 2)) = v
If you want to ignore the final line break [{:#:}], could add this line at the top of the function:
If Right(phpString, 7) = "[{:#:}]" Then phpString = Left(phpString, Len(phpString) - 7)
This wasn't as easy as I originally thought. I can get rid of one loop easily. But there's still an if test, so it doesn't break on empty strings etc. I feel a guru could make this even more efficient.
My worry is that for you this process is taking a lot of time. If you are trying to speed things up, your code doesn't look too horribly inefficient.
More likely if it's running slowly, is that the application.calculation & application.screenUpdating settings are set incorrectly.
Sub takePHP(myString As String)
'This sub takes specially formatted strings from a PHP script,
'and parses into rows and columns
Dim myRows As Variant
Dim myCols As Variant
Dim subRow As Variant
Application.ScreenUpdating = False
Application.Calculation = xlCalculateManual
myRows = Split(myString, "[{:#:}]")
x = 1
For Each subRow In myRows
bob = Split(subRow, "[|:#:|]")
If UBound(bob) <> -1 Then
Range(Cells(x, 1), Cells(x, UBound(bob) + 1)).Value = bob
x = x + 1
End If
Next
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub

Resources