Delete row if first letter in cell is a letter - vba

I am trying to loop through a range in column A and delete each row where the value in cell A starts with a letter (e.g. delete C159, but not 8T9G3). I think the code may work correctly, if I get the between piece straight. Any suggestions how I can get the code to work?
Sub DeleteLetterRows()
Dim k as integer
For k = 2 To 100
If Asc(ActiveSheet.Range("A" & k).value) >=65 and <=90 or >=97 and <=122
Rows(k).EntireRow.Delete
Else
End If
Next k
End Sub
Thanks!

Some issues:
When you delete a row, and k increases, you actually skip a row, which you don't check. So, better go downwards with k to avoid this problem.
The way you compare against ASCII values has wrong syntax, as you need to explicitly specify a value after and immediately before each >= and <= operator. But instead of giving a correction (which would be long), I'll suggest a shorter syntax:
Checking for a letter can be done in a more readable way, which does not require the knowledge of ASCII codes. Simply check if the first character is different when put in upper case than when put in lower case. If so, it is a letter.
You are missing the Then keyword at the end of the If line;
Code:
Sub DeleteLetterRows()
Dim k as integer
Dim l as String
For k = 100 To 2 Step -1
l = Left(ActiveSheet.Range("A" & k).value, 1)
If UCase(l) <> LCase(l) Then
Rows(k).EntireRow.Delete
End If
Next k
End Sub

To check the first character of your string you use the function Left().
The easiest way to find out if is not a number is the function isNumeric().
Put together you will get
Sub DeleteLetterRows()
Dim k as integer
Dim test As String
For k = 2 To 100
test = Left(ActiveSheet.Range("A" & k).value,1)
If isNumeric(test) = False then
Rows(k).EntireRow.Delete
Else
End If
Next k
End Sub

Related

Extract first two digits that comes after some string in Excel

I have a row with values something like this, How to extract first two digits that come after the text 'ABCD' to another cell, any formula or vba? There may be a few chars in between or sometimes none.
ABCD 10 sadkf sdfas
ABCD-20sdf asdf
ABCD 40
ABCD50 asdf
You can do this with a worksheet formula. No need for VBA.
Assuming you do not need to test for the presence of two digits:
=MID(A1,MIN(FIND({1,2,3,4,5,6,7,8,9,0},A1&"1234567890")),2)
If you need to test for the presence of two digits, you can try:
=IF(ISNUMBER(-RIGHT(MID(A1,MIN(FIND({1,2,3,4,5,6,7,8,9,0},A1&"1234567890")),2),1)),MID(A1,MIN(FIND({1,2,3,4,5,6,7,8,9,0},A1&"1234567890")),2),"Invalid")
In general, it is always a good idea to show some code in StackOverflow. Thus, you show that you have tried something and you give some directions for the answer.
Concerning the first two digits extract, there are many ways to do this. Starting from RegEx and finishing with a simple looping of the chars and checking each one of them.
This is the loop option:
Public Function ExtractTwoDigits(inputString As String) As Long
Application.Volatile
Dim cnt As Long
Dim curChar As String
For cnt = 1 To Len(inputString)
curChar = Mid(inputString, cnt, 1)
If IsNumeric(curChar) Then
If Len(ExtractTwoDigits) Then
ExtractTwoDigits = ExtractTwoDigits & curChar
Exit Function
Else
ExtractTwoDigits = curChar
End If
End If
Next cnt
ExtractTwoDigits = -1
End Function
Application.Volatile makes sure that the formula recalculates every time;
-1 is the answer if no two digits exist in the inputString;
IsNumeric checks whether the string inside is numeric;
As a further step, you may try to make the function a bit robust, extracting the first 1, 3, 4 or 5 digits, depending on a parameter that you put. Something like this =ExtractTwoDigits("tarato123ra2",4), returning 1232.
RegEx Version:
Public Function GetFirstTwoNumbers(ByVal strInput As String) As Integer
Dim reg As New RegExp, matches As MatchCollection
With reg
.Global = True
.Pattern = "(\d{2})"
End With
Set matches = reg.Execute(strInput)
If matches.Count > 0 Then
GetFirstTwoNumbers = matches(0)
Else
GetFirstTwoNumbers = -1
End If
End Function
You have to enable Microsoft Regular Expressions 5.5 under extras->references. The pattern (\d{2}) matches 2 digits, return value is the number, if not existing -1.
Note: it only extracts 2 successive numbers.
If you place this function into a module, you can use it like normal formula.
Here a great site to to get into regEx.

Finding max value of a loop with VBA

I am trying to find max value of a loop. First, I have two random arrays and I want to find these two arrays correlation coefficient. Then, I want to calculate it multiple times as much as "I3" cell. After that, I want to write a code which finds max correlation coefficient from this calculation. I wrote the code below but it didn't work.
Sub Macro1()
Dim i As Long
For i = 1 To Range("I3")
Calculate
Next
DMax = Application.WorksheetFunction.Max("A2")
Range("I4").Value = DMax
End Sub
Any help is appreciated.
Your Max-Function needs a proper argument. Just typing "A2" doesn't work in VBA. Try:
DMax = Application.WorksheetFunction.Max(Range("A2"))
This will give you the max-Value of the Array A2. But keep in mind that the max-Value of a range consisting of a single cell is always the cell value.
If you want to calculate the maximum value of all iterations, you should use the max-function in each iteration (inside for-loop) and store it's value. In each following iteration you should then overwrite the max-Value if your new max value is larger than the old one. Just like this:
Sub Macro1()
Dim i As Long
DMax = 0
For i = 1 To Range("I3")
Calculate
DMax2 = Application.WorksheetFunction.Max(Range(...))
If DMax2 > DMax Then DMax = DMax2
Next i
Range("I4").Value = DMax
This will give you the max-Value of Range(...) of all iterations.
I barely understand your code, but the solution will be nasted loop. Suppose you have two sets of numbers: A2 (Cells(2, 1)) through I2 (Cells(2, 7)) and A3 (Cells(3, 1)) through I3 (Cells(3, 7)). You want to calculate partial correlation and find what was the maximum value of it.
For i = 1 To 7
For j = 1 To i
'Calculate the correlation
Next j
'here you have partial coefficient and you can compare it,
'if it is greater than previous one then save it and store
Next i
For i = 1 To Range("I3").value 'to calculate from 1 to the value in that cell
what i would recommend for your question.
For i = 1 To 10 ' loop 10 times
For j = 1 To i ' here it will allow you to check your stuff multiple times before moving on to the next value
arr1(i) = arr2(j) ' see if your array match
Next j
Next i

If cells in specific sheet equal a specific value, then delete the row

I am checking all cell in a range. If a cell's value is equal to 0 (the value is generated by a formula) then delete the row.
Sub CleanJunk()
For Each c In Worksheets("testsheet").Range("B33:B533").Cells
If c.Value = "0" Then Rows(c.Row).EntireRow.Delete
Next
End Sub
Right now the module runs without any error. It just doesn't do anything. No rows get deleted or affected in any way.
You haven't qualified the Rows call, and you need to loop backwards:
Sub CleanJunk()
Dim n as long
for n = 533 to 33 step -1
If Worksheets("testsheet").Cells(n, "B").Value2 = 0 Then Worksheets("testsheet").Rows(n).EntireRow.Delete
Next
End Sub
The key here is that the value is generated by a formula. It probably contains a floating point error.
Comparing a value to a string "0" isn't good coding either - apples with apple not oranges!
To get rid of the floating point error use the `ROUND(Num, # of decimals) with # of decimals = 0
Compare the result to 0.
Option Explicit 'so you don't confuse your variables
Sub CleanJunk()
Dim c as range
For Each c In Worksheets("testsheet").Range("B33:B533").Cells
'compare values rounded to integer with 0
If Round(c.Value, 0) = 0 Then c.EntireRow.Delete
Next c 'it pays to be explicit
End Sub

Excel VBA - how to populate a range with COUNTIF values that reference non-consecutive columns

Disclaimer: I realize that this is easy to solve by just forumlating the TALLY column within the table, but this is more of an exercise in learning VBA in general.
I have table in my worksheet that has multiple columns of "Yes" or No", and I would like to find a way in VBA to tally the No's in a separate column. Here is an example of what I am trying to describe:
I figure it involves a loop somehow which would include Application.WorksheetFunction.CountIf, but short of doing a really messy Union range to reference I cannot figure how to code this effectively. Thank you in advance for any ideas posited.
Something like formula:
=COUNTIF(C:C,K1)+COUNTIF(F:F,K1)+COUNTIF(I:I,K1)
where K1 contains the value in C:C, F:F, and I:I that you want to count.
now if you need to count in ANY column you could just set the all the columns and do countif()
such as =COUNTIF(A:I,K1) but any occurrence within A:I will be counted if Yes/No.
also note this is case insensitive.
I'd do it like this (NOT with Countif):
Sub countCond()
Dim cond As String
Dim i As Long
Dim countCond As Long
Dim column As Variant
cond = "No" 'You can set this to 'Yes' as well
With Sheet1 'Or Worksheets("Sheet1") 'or whatever you have
For i = 1 To .Range("TALLY").Cells.Count
'I suggest naming it (at least the sum column)
'--Edit: Without the header, so just the values.
For Each column In .UsedRange.Columns
'Or maybe instead UsedRange, name the section
'that contains these columns
If column.Cells(1).Value Like "*COMP" Then 'Assuming this is true
If column.Cells(i + 1) = cond Then countCond = countCond + 1
End If
Next
.Range("TALLY").Cells(i, 1).Value = countCond
countCond = 0
Next i
End With
End Sub
This way, your code manually counts the cond variable in every row for every column that looks like *COMP.
Hope it helps.
Thank you all for your input, I believe I found an answer to my problem. Using this code I was able to get the results I wanted:
Sub Test()
Dim Fx() As Variant
Dim i As Integer
Dim tg_row As Integer
Fx() = Array("Table1", "[EXAComp]", "[EXBComp]", "[EXCComp]")
For Each cl In Range("Table1[TALLY]")
For i = 1 To 3
If Range(Fx(0) & Fx(i)).Cells(tg_row, 1).Value = "No" Then
cl.Value = cl.Value + 1
Else: cl.Value = cl.Value + 0
End If
Next
tg_row = tg_row + 1
Next cl
End Sub

VBA - Select columns using numbers?

I'm looking for an alternative to this code, but using numbers.
I want to select 5 columns, the start column is a variable, and then it selects 5 columns from this.
Columns("A:E").Select
How do I use integers instead, to reference columns? Something like below?
For n = 1 to 5
Columns("n : n + 4") .select
do sth
next n
You can use resize like this:
For n = 1 To 5
Columns(n).Resize(, 5).Select
'~~> rest of your code
Next
In any Range Manipulation that you do, always keep at the back of your mind Resize and Offset property.
Columns("A:E").Select
Can be directly replaced by
Columns(1).Resize(, 5).EntireColumn.Select
Where 1 can be replaced by a variable
n = 5
Columns(n).Resize(, n+4).EntireColumn.Select
In my opinion you are best dealing with a block of columns rather than looping through columns n to n + 4 as it is more efficient.
In addition, using select will slow your code down. So instead of selecting your columns and then performing an action on the selection try instead to perform the action directly. Below is an example to change the colour of columns A-E to yellow.
Columns(1).Resize(, 5).EntireColumn.Interior.Color = 65535
you can use range with cells to get the effect you want (but it would be better not to use select if you don't have to)
For n = 1 to 5
range(cells(1,n).entirecolumn,cells(1,n+4).entirecolumn).Select
do sth
next n
Try using the following, where n is your variable and x is your offset (4 in this case):
LEFT(ADDRESS(1,n+x,4),1)
This will return the letter of that column (so for n=1 and x=4, it'll return A+4 = E). You can then use INDIRECT() to reference this, as so:
COLUMNS(INDIRECT(LEFT(ADDRESS(1,n,4),1)&":"&LEFT(ADDRESS(1,n+x,4),1)))
which with n=1, x=4 becomes:
COLUMNS(INDIRECT("A"&":"&"E"))
and so:
COLUMNS(A:E)
In the example code below I use variables just to show how the command could be used for other situations.
FirstCol = 1
LastCol = FirstCol + 5
Range(Columns(FirstCol), Columns(LastCol)).Select
no need for loops or such.. try this..
dim startColumnas integer
dim endColumn as integer
startColumn = 7
endColumn = 24
Range(Cells(, startColumn), Cells(, endColumn)).ColumnWidth = 3.8 ' <~~ whatever width you want to set..*
You can specify addresses as "R1C2" instead of "B2". Under File -> Options -> Formuals -> Workingg with Formulas there is a toggle R1C1 reference style. which can be set, as illustrated below.
I was looking for a similar thing.
My problem was to find the last column based on row 5 and then select 3 columns before including the last column.
Dim lColumn As Long
lColumn = ActiveSheet.Cells(5,Columns.Count).End(xlToLeft).Column
MsgBox ("The last used column is: " & lColumn)
Range(Columns(lColumn - 3), Columns(lColumn)).Select
Message box is optional as it is more of a control check. If you want to select the columns after the last column then you simply reverse the range selection
Dim lColumn As Long
lColumn = ActiveSheet.Cells(5,Columns.Count).End(xlToLeft).Column
MsgBox ("The last used column is: " & lColumn)
Range(Columns(lColumn), Columns(lColumn + 3)).Select
In this way, you can start to select data even behind column "Z" and select a lot of columns.
Sub SelectColumNums()
Dim xCol1 As Integer, xNumOfCols as integer
xCol1 = 26
xNumOfCols = 17
Range(Columns(xCol1), Columns(xCol1 + xNumOfCols)).Select
End Sub