How do I "AND" across a range of cells in VBA? - excel

Given that I have a range of cells (say A1:F1), in which all those cells contain either TRUE or FALSE. I know that I can write the formula =AND(A1:F1) in G1 which will "AND" across that range and return either TRUE or FALSE to G1.
My question is how would I do the something in VBA? Everything I find leads me to believe that I have to write code that looks something like
If A1 And B1 And C1 And D1 And E1 And F1 Then ...
But there must be a better way.
I've tried Var = And(A1:F1) and Var = Application.WorksheetFunction.And(A1:F1) both result in a line of red code.
I sure it's simple but I can't seem to find it.

Related

How can I substitute a cell reference for the formula the referred cell contains

How can I substitute a cell reference for the formula it contains, in other words, "expand" or "derivate" cell references?
An example, and I know I could calculate it using PV(): Suppose I want to calculate the present value of a given amount, reductor, number of periods and discount rate and in a spreadsheet I have:
A2: 1 (number of periods)
B2: 5000 (amount)
C2: 0,8 (reductor)
G1: 6% (discount rate)
If I want to calculate the final result on D2, I would have to enter:
=(B2*C2)*(1+$G$1)^(-A2)
(I intentionally used some unnecessary parentheses above)
But if I wanted, for debugging, or for building a more complex formula with more nested calculations write on cells:
D2: =E2*F2^G2
E2: =B2*C2
F2: =1+$G$1
G2: =-A2
So that I could check every part of the calculation is working ok and that the final formula is well "assembled" (or to easily correct what might be wrong or change it to calculate something else, like future value, for which I would remove the minus sign on G2).
And after doing those steps use some function/shortcut/feature on cell D2 that would replace
"=E2*F2^G2"
for
"=(B2*C2)*(1+$G$1)^(-A2)"
(i.e. do E2 → (B2*C2) F2 → (1+$G$1) and G2 → (-A2)) so that the desired formula is built on the right place and I can get rid of the temporary cells.
The closest to this behaviour I could find was formulatext() function, but it works just for a single reference and always include the "=" if I do, for instance
=CONCAT(FORMULATEXT(E2);"*";FORMULATEXT(F2);"^";FORMULATEXT(G2))
results in
=B2*C2*=1+$G$1^=-A2
which is not the desired result.
What I was expecting to find was something like when one select a part of a formula and presses F9 and it substitutes it for the value, but applied for functions or intermediate steps.
As it really does not seem to exist a built-in funcion on Excel, I came out with a script for doing this based on the answer on Parsing and extracting cell references from Excel formulas?
Works on Excel 365 (may work on other versions as well), replaces references on active cell only, does not work on cells that contain intervals (for instance, it will fail on a cell that contains =sum(A1:A5) ) and the contents of the precedent cells will end up enclosed in parentheses. It also does not replace "locked" cells (=$B$2 won't be replaced as well).
In summa, it is not perfect, maybe it's not ellegant too, but it seems to be as good as I needed and works on the proposed scope.
Sub ReplacePrecedents()
Dim r As Range, rr As Range
With ActiveCell.Range("A1")
' store the contents of the cell
parsedcontents = .Formula
Set r = .DirectPrecedents
' iterate throughout all precedents
For Each rr In r
' store each one between parentheses
appendstr = "("
' check whether first character is a "=" or a value
If StrComp(Left(rr.Range("A1").Formula, 1), "=") = 0 Then
appendstr = appendstr & Right(rr.Range("A1").Formula, Len(rr.Range("A1").Formula) - 1)
Else
appendstr = appendstr & rr.Range("A1").Formula
End If
appendstr = appendstr & ")"
' do the magic
parsedcontents = Replace(parsedcontents, rr.Address(0, 0), appendstr)
Next rr
' write the parsed string to the cell
.Formula = parsedcontents
End With
End Sub
Thank you for everyone that replied, I guess I still do not have privileges enough to upvote a comment, as soon as I do, I will.

Weirdness of results in array-style Search function

When I put a set of formulas in excel 2013 like this:
A1 = abc
A2 = ac
A3 = bc
B1 = OR(TRUE) = TRUE
B2 = OR(FALSE) = FALSE
B3 = ISNUMBER(SEARCH({"a", "b"}, A1)) = TRUE
B4 = ISNUMBER(SEARCH({"a", "b"}, A2)) = TRUE
B5 = ISNUMBER(SEARCH({"a", "b"}, A3)) = FALSE
Yet if I add an OR function in the formulas :
C1 = OR(ISNUMBER(SEARCH({"a", "b"}, A1))) = TRUE
C2 = OR(ISNUMBER(SEARCH({"a", "b"}, A2))) = TRUE
C3 = OR(ISNUMBER(SEARCH({"a", "b"}, A3))) = TRUE
Logically the input reveived by the OR function in cell C3 is supposed to be FALSE (see B5 and compare it with B2) yet it resulted in TRUE when it supposed to result in FALSE. I want to know why is this happening? Is there an explanation for this? And does this happen in all version of excel after 2007?
Another interesting fact is that if I take the result in B5 as the direct input of an OR function like so:
C4 = OR(B5) = FALSE
It resulted in FALSE yet it is basically the same formula as C3. Why does this inconsistency happens? Is it a bug?
Updated question
According to the answers below, the OR function is an "array-friendly" function. What does that exactly mean? And how would a beginner like me know which function in excel are "array friendly" and which are not? Is there a list as such?
Also does this mean that the SEARCH and ISNUMBER function aren't "array friendly"? Yet it accepts "array" as an argument. I'm confused.
OR can take multiple arguments, or evaluate all items from an array...
ISNUMBER(SEARCH({"a","b"}, A3)) returns a single value in context of displaying formula result in a single cell, but it returns an array in array-friendly context such as inside OR (I don't know the exact name of this feature though.)
OR({FALSE, TRUE}) is TRUE, similar to OR(ISNUMBER(SEARCH("a", A3)), ISNUMBER(SEARCH("b", A3))).
Update after changing the question:
All of the intermediate functions must be array-friendly for this to work (I believe most functions are, but I am not aware of any list - you have to do some research yourself, this is not paid support).
The single cell output is NOT array friendly. When a result is an array, e.g. {TRUE, FALSE} and it's displayed in a single cell, only the first value will be visible in the cell.
More on array formulas where 1 formula can be inserted into multiple cells: https://support.office.com/en-us/article/create-an-array-formula-e43e12e0-afc6-4a12-bc7f-48361075954d

Dynamically select the Conditional Formatting range based on a cell value

looking for a conditional formatting trick to do this.
if value of Cell A1 = 1 then cell B1 should be Formatted. If the value of A1 = 2 then Cell B2.
conditional Formatting range should be changed dynamically based on value of cell A1.
This can be easily solved with Conditional Formatting, no need for VBA.
Mark your cells B1+B2, Choose Conditional Formatting (from Home-Tab), New Rule, Select "Use a formula...", enter =$A$1=ROW() as formula and set the Format to whatever you want.
UPDATE (after your comment what you want to format)
If the ranges you wan to format are always the same size and with the same distance, you can use a formula like
=AND(MOD(COLUMN()-1,4)>0,INT((COLUMN()-1)/4)+1=$A$1,ROW()>=5,ROW()<=10)
This checks if the row is between 5 and 10 and divide the column by 4 to check in which "block" you are. The Mod-part prevents the formatting of col A, E...
If the blocks you want to format are more complicated, you could solve this with an UDF:
Public Function calcFormattingVal(r As Range) As Integer
If Not Intersect(Range("B5:D10"), r) Is Nothing Then
calcFormattingVal = 1
ElseIf Not Intersect(Range("F5:H10"), r) Is Nothing Then
calcFormattingVal = 2
Else
calcFormattingVal = -999
End If
End Function
Now, put the following formula as conditional formatting. Be aware that you have to pass the address of upper left cell where your formatting starts as parameter to the function. So if you mark the range "B5:H12", use B5 as parameter.
=calcformattingval(B5)=$A$1

Print equations components in a text box - excel vba

I'm trying to build a toll to make data analysis. I want to code a text box that will show the values that compound the result of each cell I select. For instance: the cell A1 contains the value "2", the cell B1 contains the value "3" and the cell C1 is =A1*B1 , so "6". I want to add a text box that when I select the cell C1 will bring the text "2*3" instead of "A1*B1" as it shows in the formula bar. Does anyone knows how to do it?
The challenge you're going to face is this: there is no such thing as a "formula" object in the Excel object model, because a formula is a string of essentially arbitrary length and construction, arbitrary levels of nesting and cell references/precedents, each of which may contain a formula (which would require some recursion) or a constant, etc. There is no "general" way to parse these things, although as the linked answer indicates, there are some tools out there which may do something similar.
If you have specific cases, you can probably hack something that will work for those cases, but will not be generally applicable to other formulae. Using a range object's .DirectPrecendents, you can trace cells which are referred to in the formula, and using some string functions you may be able to reverse-engineer the formula to constant expressions, and recombine with the operators. HOWEVER, my own testing shows this to be fraught with problems because each of these formula will return the same list of DirectPrecedents:
=$A1*$B1
=$A$1*$B$1
=$A$1*B1
=A1*B1
In those cases (and others), the precedents will be the ranges A1 and B1, respectively, but each of those variants would require that you can identify whether the row and/or column in each precedent is "absolute", at runtime, otherwise, any attempts to use string functions like Mid, Left and Instr will likely fail or return false positives.
If your formula are exceedingly simple, and you know you are always dealing with ONLY references, each of which contain constant expressions (not other formula refernces), e.g.:
=$A$1*B$1 'Where A1 contains a constant and so does B1
You could do something like:
Function parseFormula(cl as Range, operator as String)
Dim arr, i As Long
Dim ret As String
ret = "="
arr = Split(Mid(cl.Formula, 2), operator)
' yields an array like {$A$1, $B1}
For i = 0 To UBound(arr)
If (i = 0) Then
ret = ret & Range(arr(i)).Value
Else
ret = ret & operator & Range(arr(i)).Value
End If
Next
parseFormula = ret
End Function
Of course this will not work for for formula with mixed operators like:
=A1+B1/C1
Nor will it work for formula which mix constants and references like:
=65+B2/C1

How to use plus or minus in a cell inside a formula in another cell

I'm trying to do some stuff with solver but the results I need, I need to put the operators to the formula in another cell.
So, to be pratical, should be some like this:
A1 = <
A2 = >
A3 = <=
A4 = >=
B1 = 20
B2 = 30
C1 = =B1&A1&B2
The formula needs to understand the the data inside A1 to A4 are operators.
Any ideas?
Thanks!
As far as I'm aware, you can't do this in the traditional sense. What you can however do, is the following.
Select cell "C1"
Go to the formulas tab
Define a name
Name it something descriptive, like "Eval1" or whatever
Refer it to =EVALUATE(Sheet3!$A2&Sheet3!A$1&Sheet3!$B2)
Be aware that this uses relative selection, writing =Eval1 in cell G2 would not work in this case because it would try and evaluate A2 & E1 & B2 but can work if you adapt the refer to of eval1 in the name manager.

Resources