How can I simplify this into one sentence in vba?
If [BT12] = "a" Then
Range("AB12").ClearContents
End If
If [BT13] = "a" Then
Range("AB13").ClearContents
End If
If [BT14] = "a" Then
Range("AB14").ClearContents
End If
Here it is in one line:
[AB12:AB14] = [IF(BT12:BT14 = "a","",AB12:AB14)]
Here is another using UNION:
Union(IIf([BT12] = "a", [AB12], [AFD1040000]), IIf([BT13] = "a", [AB13], [AFD1040000]), IIf([BT14] = "a", [AB14], [AFD1040000])).ClearContents
The first creates an array of the values, either "" or the value in the cell. It is very concise and can easily be expanded to include a larger range. The drawback is that if the data in AB is filled by formula the formula will be replaced by the value and the formula will be removed.
The second only clears those that need to be cleared leaving the others unchanged but is not as easily editable with larger ranges.
This is bad practice and not recommended but is a one-liner. It is expected that this would be wrapped in a With statement holding the parent sheet reference.
Dim i As Long: For i = 12 To 14: If .Cells(i, 72).Value = Chr$(97) Then .Cells(i, 28).ClearContents: Next
here's your one-sentence code:
If Not [BT12:BT14].Find("a", , xlValues, xlWhole) Is Nothing Then Range(IIf([BT12] = "a", IIf([BT13] = "a", IIf([BT14] = "a", "AB12:AB14", "AB12:AB13"), IIf([BT14] = "a", "AB12,AB14", "AB12")), IIf([BT13] = "a", IIf([BT14] = "a", "AB13:AB14", "AB13"), IIf([BT14] = "a", "AB14", "")))).ClearContents
that you can (possibly) read more comfortably as:
If Not [BT12:BT14].Find("a", , xlValues, xlWhole) Is Nothing Then Range( _
IIf([BT12] = "a", _
IIf([BT13] = "a", _
IIf([BT14] = "a", "AB12:AB14", "AB12:AB13"), _
IIf([BT14] = "a", "AB12,AB14", "AB12") _
), _
IIf([BT13] = "a", _
IIf([BT14] = "a", "AB13:AB14", "AB13"), _
IIf([BT14] = "a", "AB14", "") _
) _
) _
).ClearContents
Yes, it can be done :-)
Just for fun: assuming you provide an ► empty cell in [AB11], you can use this one liner via the Application.Index function:
[AB11:AB14] = Application.Transpose(Application.Index([AB11:AB14], Array(1, IIf([BT12] = "a", 1, 2), IIf([BT13] = "a", 1, 3), IIf([BT14] = "a", 1, 4)), 1))
(Edit thx DisplayName:)
Amplifying remarks to the Index function
You can find amplifying remarks to the use of the Index function at Insert first column in array without Loops or API calls
For what you are asking for; the IIF function works, whether you are evaluating using a True or False clause. Try this one liner.
For Each cel In Range("BT12:BT14"): IIf cel = "a", cel.Offset(, -44).ClearContents, True: Next
How can I simplify this into one sentence in vba?
Should you? Your example code is concise, and easy to read. As Rawrplus points out, shorter for the sake of being shorter is usually not a good idea.
One could simplify each line to this:
If [BT12] = "a" Then Range("AB12").ClearContents
If [BT13] = "a" Then Range("AB13").ClearContents
If [BT14] = "a" Then Range("AB14").ClearContents
Is that better? Arguably no in my opinion. If the actions of the condition ever need more complexity, you'll be forced to refactor anyway.
The quick answer is: it cant' be done. But one could figure out a solution if one want's to although it be rather far fetched.
First create a sub to put in a library module.
Sub ClearCellContent(ParamArray Args())
Dim i As Integer, J As Integer
i = UBound(Args)
For J = 0 To i Step 3
If Args(J).value = Args(J + 1) Then Args(J + 2).ClearContents
Next
End Sub
From a somewhere in your code you can now call this sub like so:
ClearCellContent [BT12], "a", [AB12], [BT13], "a", [AB13], [BT14], "a", [AB14]
Like I said, far fetched but a oneliner of sorts.
Related
I am getting run time error 6: Overflow through the below code.
n = (.Cells(Rows.Count, "A").End(xlUp).Row)
FillP = Array("D", "E", "F", "H", "I", "J", "M", "O", "P", "AR", "AS", "BE", "BF", "BG", "BH", "BI", "BJ", "BK", "BL", "BQ", "BR", "BS", "BT", "BU", "BV", "BW", "BX", "BY", "CB", "CC", "CD")
'fill blanks with na
For i = 2 To n
For j = LBound(FillP) To UBound(FillP)
If Trim(.Range(FillP(j) & i)) = "" Then
.Range(FillP(j) & i) = "na"
End If
Next j
Next i
I have Excel 2010, I haven't yet declared any of the above variables yet (will do after testing). Just trying to fill blanks in specific columns with an "na". Nearly identical code appears earlier in my sub and yet it runs fine. No idea where i'm going wrong.
Thanks in advance for any help!
overflow results when you try to assign value to a variable, that exceeds the limitations of the data type.
I am afraid that you might have declared i, j, or n as Interger.
Also you will not need the dot operator before cells & range.
Where does the error specificaally occur? just from inspection, you do not need the dots before Cells and Range. You would only do that in a with statement
What is shortcut of checking string value like this.
If midtxt = "a" Then
midtxt = "apple"
ElseIf midtxt = "b" Then
midtxt = "ball"
ElseIf midtxt = "c" Then
midtxt = "cat"
.....
ElseIf midtxt = "z" Then
midtxt = "zebra"
End If
MsgBox midtxt
Is there any way I can do this using two arrays.
[a, b, c....z] and [apple, ball, cat.....zebra]
Edit
I need reproducible function for my task.
I think a for apple is not right example for me.
This is updated array for me.
[ap, bl, ca,... zr] [apple, ball, cat... zebra]
means the two letter code is derived from the corresponding string but it is not uniformly derived.
A dictionary may be worthwhile here, as long as the [a, b, ...z] set is unique.
In the VBA IDE, go to Tools, References, and select Windows Scripting Runtime.
Public gdctAnimals As Dictionary
Public Sub SetUpAnimalDictionary()
Set gdctAnimals = new Scripting.Dictionary
gdctAnimals.Add "a", "apple"
gdctAnimals.Add "b", "ball"
gdctAnimals.Add "c", "cat"
gdctAnimals.Add "z", "zebra"
End Sub
Public Sub YourProc(midtxt As String)
If gdctAnimals Is Nothing Then
SetUpAnimalDictionary
End If
If gdctAnimals.Exists(midtxt) Then
MsgBox gdctAnimals(midtxt)
Else
MsgBox "Item not found in dictionary", vbExclamation
End if
End Sub
Use the Select Case or Switch function
Function SwapString(strInput As String)
SwapString= Switch(strInput = "a", "Apple", strInput = "b", "Banana", strInput = "c", "Cherry")
End Function
In your case, if you can only have 26 combinations (a-z) the easiest way is to do this:
Public Function ReturnString(strIn As String) As String
Select Case strIn
Case "a"
ReturnString = "apple"
Case "b"
ReturnString = "ball"
Case "c"
ReturnString = "cat"
' .............
Case Else
ReturnString = "UNKNOWN"
End Select
End Function
and you call your fonction like this
MyLongString = ReturnString "a"
But there are many more possibililities that I won't detail because you have not detailed enough your question:
You can use 2 arrays or a 2D array
you can use an array of private types
you can use a dictionary as specified in another answer
No need for an external component or tedious population, you are looking for something based on an ordinal value; a=>z is the character code range 97=>122 so you can use a simple efficient array lookup by converting the character code to a value within the bounds of the array:
'//populate (once)
Dim map() As String: map = Split("apple,ball,cat,...,zebra", ",")
'//lookup
midtxt = "a"
midtxt = map(Asc(Left$(midtxt, 1)) - 97)
'=>apple
midtxt = "c"
midtxt = map(Asc(Left$(midtxt, 1)) - 97)
'=>cat
If needed check the value starts with a character first with if midtxt like "[a-z]*" then ...
My title might not be clear so I'll try to explain it with an example.
Let's say I have an excel sheet with one column for city names and another column for state names and a third column for country names. I want to loop through the columns and in a 4th column print what was found in the other 3 columns. So let's say column one is "Houston", column two is "Texas", and column three is "USA", how would I print to the fourth column "HTXUSA"? I have almost no experience in VB in Excel so I'm hoping someone will be able to help.
I searched for similar topics but couldn't find anything that was helpful. A couple threads helped a little bit, but I still don't have this figured out.
To get you started, here is a VBA solution. It uses a public Dictionary object. These really come from VBScript but can be used in VBA in a couple of ways, including by CreateObject. The dictionary is initialized just once, the first time the corresponding Abbreviate function is called. This function takes a range, and for each cell in the range sees if there is a corresponding dictionary key. If so -- the corresponding value is concatenated onto the growing string, if not -- the value itself is. I am making keys upper case so as to make everything case-insensitive:
Public Abbreviations As Variant
Public Initialized As Boolean
Sub Initialize()
Dim A As Variant, i As Long, n As Long
'modify the following:
A = Array("Houston", "H", "Dallas", "D", "Cleveland", "C", _
"Toronto", "T", "Texas", "TX", "Ohio", "OH", _
"Ontario", "ON", "Canada", "CAN")
n = UBound(A) - 1
Set Abbreviations = CreateObject("Scripting.Dictionary")
For i = 0 To n Step 2
Abbreviations.Add UCase(A(i)), A(i + 1)
Next i
Initialized = True
End Sub
Function Abbreviate(R As Range) As String
Dim i As Long, s As String
Dim cell As Range
If Not Initialized Then Initialize
For Each cell In R.Cells
If Abbreviations.exists(UCase(cell)) Then
s = s & Abbreviations(UCase(cell))
Else
s = s & UCase(cell)
End If
Next cell
Abbreviate = s
End Function
A screenshot of how it works:
I'm attempting to take the text in each cell of column A and assign a value to each cell in column B depending on the text in column A. For example, I have a list of versions that are identified by four-letter abbreviations of cities, and all of those versions are regionally assigned to different factories to be produced. So let's say I have an "AUST", "DAFW", "HOUS", and more versions all assigned to the location of "ARLINGTON". How would I most concisely use VBA to automate that once I have all the versions plugged in? Something like
If A2="AUST" Then
B2="ARLINGTON"
ElseIf A2="DAFW" Then
B2="ARLINGTON"
I suppose something like this would work, however I can't believe that there's not a faster and more concise way. Does this make any sense? I've been pulling my hair out for about a week now trying to figure this out... Thanks for any help!
This is a little simpler using OR:
If A2="AUST" OR A2="DAFW" Then
B2="ARLINGTON"
ElseIf A2 = "ABCD" OR A2 = "WZYZ" Then
B2="SOMETHING"
'ETC...
However, if you are iterating over column A, the variable "A2" is strange. But I am not sure how you are doing this. Maybe supply more code and we can help you more.
This could be done with excel formulas as well, though I always prefer to use VBA. This should work the way you want :
Sub yourFunk()
Set wb = ThisWorkbook
Set ws = wb.Sheets(1)
arlington = Array("AUST", "DAFW", "HOUS")
otherLocation = Array("XXXX", "YYYY", "ZZZZ")
lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
For x = 2 To lastRow
If stringIsInArray(ws.Cells(x, 1), arlington) Then
ws.Cells(x, 2) = "ARLINGTON"
ElseIf stringIsInArray(ws.Cells(x, 1), otherLocation) Then
ws.Cells(x, 2) = "OTHER LOCATION"
End If
Next x
End Sub
Function stringIsInArray(stringToBeFound As String, arr As Variant) As Boolean
stringIsInArray = (UBound(Filter(arr, stringToBeFound)) > -1)
End Function
If you need me to explain the code, please do let me know :)
The fastest way is to use Dictionary.
Let's say, your data is present in the following range:
A2 = "AUST"
A3 = "DAFW"
Now, check this code:
'Needs reference to Microsoft Scripting Runtime
Sub Translate()
Dim dic As Dictionary
Dim i As Integer, sTmp As String
Set dic = New Dictionary
dic.Add "AUST", "ARLINGTON"
dic.Add "DAFW", "ARLINGTON"
For i = 2 To 3
sTmp = ThisWorkbook.Worksheets(1).Range("A" & i)
Debug.Print sTmp, "-", dic(sTmp)
Next
Set dic = Nothing
End Sub
Note: This code is just an example!
For further information please see: https://msdn.microsoft.com/en-us/library/office/gg251825.aspx
Okay this one might be a little tougher. I'm using VB that looks like this:
string = Replace(string.ToLower, chr(63), "A")
But I also want chr(63) = "B" as well, like this:
string = Replace(string.ToLower, chr(63), "B")
My problem is that when chr(63) is at the end of a string I need it to be B, and when it's not the end I need it to be A. I suppose that I can use an if/then/else statement. Is there a way to do this?
Example:
XXXXXchr(63)XXXXX = A
but
XXXXXXXXXXchr(63) = B
Thanks!
pseudo:
if (string[string.Length] == chr(63))
{
string[string.Length] = B
}
string = Replace(string.ToLower, chr(63), "A")
string = Replace(string.ToLower, chr(63), "A", 1, Len(string) - 1)
If Right(string, 1) = chr(63) then
Mid$(string, Len(string), 1) = 'B'
End if
Update: in response to comment:
VB String Functions
VB String Array Functions - Split, Join, Filter (very useful)
I haven't used Visual Basic since version 6, but it should be something like this:
If Robert.EndsWith(chr(63)) Then
Robert = Left(Robert, Robert.Length - 1) + "B"
End If
Then do the usual replacement with A.
This ought to do it
Dim s As String
Dim char63 As String = Convert.ToChar(63).ToString
If s.EndsWith(char63) Then
s = s.Substring(0, s.Length - 1) & "B"
End If
s = s.Replace(char63, "A")