Does Excel have a built-in "hypothetical" function? - excel

I have an Excel cell with a complicated formula relating to many other cells.
Does a function exist that would allow me to look at what the value of that cell would be if I changed the value of another cell to a certain value?
Basically, I'm looking for the functionality of a simple data table in a function I can put directly in a cell. I can do this in VBA or by creating a data table, but I'm looking for a built-in method if one exists.

No.
As you have mentioned, you would be best served using a data table - there isn't an equivalent inbuilt function. The plus with data tables is that you can explicitly control their calculation

#brettdj's answer is correct. Unfortunately, I was wrong that I could do what I want even in VBA; the code below was what I was planning to write, but it does not work because functions called from a worksheet cannot change the worksheet:
Public Function Hypothetical(setthiscell As Range, tothisvalue As Variant, andobservethiscell As Range) As Variant
Dim oldvalue As Variant
oldvalue = setthiscell.Value
setthiscell.Value = tothisvalue
Dim result As Variant
result = andobservethiscell.Value
setthiscell.Value = oldvalue
Hypothetical = result
End Function
Neither Scenarios or the Solver address my problem because I want to the solution to be automated. Apparently the only way to accomplish this task is to use data tables.

Related

MS-Excel: Retrieve Row Number where VBA Function is located

I hope I'm asking this in the correct forum:
I'm writing a UDF in VBA for MS-Excel; it basically builds a status message for the transaction on that row. It steps through a series of IF statements, evaluating cell values in different columns FOR THAT ROW.
However, this UDF will reside in multiple rows. So it might be in C12, C13, C14, etc. How would the UDF know which row to use? I'm trying something like this, to no effect
Tmp_Row = Application.Evaluate("Row()")
which appears to return a null
What am I missing here ?
Thanking everyone in advance
Application.Caller is seldom used, but when a UDF needs to know who called it, it needs to know about Application.Caller.
Except, you cannot just assume that a function was invoked from a Range. So you should validate its type using the TypeOf...Is operator:
Dim CallingCell As Excel.Range
If TypeOf Application.Caller Is Excel.Range Then
'Caller is a range, so this assignment is safe:
Set CallingCell = Application.Caller
End If
If CallingCell Is Nothing Then
'function wasn't called from a cell, now what?
Else
'working row is CallingCell.Row
End If
Suggestion: make the function take its dependent cells as Range parameters (if you need the Range metadata; if you only need the values then take in Double, Date, String parameters instead) instead of making it fetch values from the sheet. This decouples the worksheet layout from the function's logic, which in turn makes it much more flexible and easier to work with - and won't need any tweaks if/when the worksheet layout changes.
Application.ThisCell
MS Docs:
Returns the cell in which the user-defined function is being called from as a Range object.
You can put it to the test using the following code:
Function testTC()
testTC = Application.ThisCell.Row
End Function
In Excel use the formula
=testTC()
and (Cut)Copy/Paste to various cells.

Save FormulaArray Evaluation to an Actual Array

Background:
I need to retrieve the values that an array formula (in the excel interface) calculates in order to loop through the results there.
Problem:
I have not found a way on how to store all the values that it calculates. I can store only the first one.
Code:
Sub test()
Dim ArrTopValues() As Long
'Fails
ArrTopValues = Application.Evaluate("=LARGE(A1:A11,{1,2,3})")
End Sub
I need to work with the 3 values that the formula can hold on the excel interface by pressing "F9"
Further thoughts
I know that I can write a UDF that recreates the Large function (or even that just evaluates the "k" on the Large function and build the Array variable that way). Please understand that I am looking how to store this array evaluations for more scenarios and a workaround to solve this has been done already to "make it work".
Use INDEX to return the array and you need to make the array a variant:
Sub test()
Dim ArrTopValues()
ArrTopValues = Application.Evaluate("=INDEX(LARGE(A1:A11,{1,2,3}),0)")
End Sub

Excel no longer calculates my fields

I have written a simple VBA function to look up a value by key in a long table of key/value pairs. It then returns that value as a Double:
Public Function GetValue(sheet As String, key As String) As Double
Dim WS As Worksheet
Dim K As Range
GetValue = 0
Set WS = ThisWorkbook.Worksheets(sheet)
If WS Is Nothing Then Exit Function
Set K = FindKeyAnywhere(WS, key)
If K Is Nothing Then Exit Function
GetValue = WS.Cells(K.Row, 5).Value
End Function
I have about 60 of these formulas in a summary sheet:
=GetValue("Data", B$41)
Where "Data" is the name of the page with key/values, and B$41 is a key. Everything was working perfectly, then...
I fat-fingered the VBA, changing the = 0 to = o and calced. Now every cell on the summary still said #VALUE. When I realized what happened, I fixed the error and recalced. However, every cell on the summary still said #VALUE.
If I click in the cell and hit return, it updated fine.
I checked, autocalculate is turned on. I also clicked calc sheet several times. Nothing.
So I went to every single cell and hit return, so they were all updated. Now they don't say #VALUE, but they still don't update when I change data on the data page.
Is there anything special I'm missing? It seems like Excel is "stuck" thinking the calculation isn't valid.
UPDATE:
Using a named range does not work well, because it has to be typed into every formula. Consider...
KEY1 KEY2 ANOTHERKEY
Data1 =GetValue(A$1,B$1)
Data2
When the user CnPs or drag-fills that formula, it will get the key and sheet automatically. If we use a range name instead, they would have to type in the name in every single cell, and there's hundreds.
Is there a way to take a string and return the named range? Like =Range(A1)
As John Coleman says: Excel does not know it needs to recalculate when something on the Data sheet changes because the precedents of your UDF do not include the range od information on the Data sheet.
You need to:
Either Make the function Volatile - but this has bad recalculation
consequences.
Or pass the range on the Data sheet that contains the information
instead of passing a string. This is the best solution.
Based on your update I think you are looking for INDIRECT, which can convert a string to a range.
But there are major downsides to INDIRECT: its volatile, single-threaded and behaves badly when the string the user gives it does not exist.
IMHO this is not a good direction to go: I would recommend you consider a redesign of your data/algorithms.

how to write results of a formula directly into an excel range by VBA code

I have a series of functions for each of listobject columns. The file is heavy and crashing, so I want just to keep the results of each formula as static values. I can allocate formula to the range and ask excel to convert the range to value. But I am wondering if there is a way to ask VBA to write only the static values in the range instead of the formula itself.
Here is what I have so far:
Sub calculate2()
Dim i As Long, t As Long
t = Timer
With Sheet3.ListObjects(1)
For i = 3 To 9
.ListColumns(i).DataBodyRange.ClearContents
.Range.Cells(2, i).Formula = sheets3.range("formula").cells(i,1).formula
.ListColumns(i).DataBodyRange = .ListColumns(i).DataBodyRange.Value
Next i
End With
Debug.Print Timer - t
End Sub
As an answer to my own question,
What I was looking for is: " application.Evaluate " I am posting that so if anyone came here by search can find the idea and the sollution I eventually found. Here is an example:
Sheet3.ListObjects(1).ListColumns(3).DataBodyRange = [IFERROR(IF(COUNTIFS(ZZ84!$B:$B,[WO],ZZ84!$E:$E,"=*V99"‌​,ZZ84!$L:$L,"<>")=1,1,0),"")]
in this case there is no need to loop and for each range has to write needful line of code (Embed the function in VBA, what I excatly was looking for). The only different in above function with directly putting that in a excel cell is using [WO] instead of [#WO]. So evaluat caculate an array of data and directly write that in specified range. (here body range of list columns 3 ).
For me it helped to avoid crashes beacause of voilate calculation by my functions.
Another simple example would be:
range("b1:b10")=[if(row(1:10),if(a1:a10>3,"big","Small"))]
or
range("b1:b10") = evaluate("if(row(1:10),if(" & range("a1:a10").address&">3,""big"",""small""))")
Kind regards,
M

Using tables in UDF's in Excel 2007

I am writing a UDF for Excel 2007 which I want to pass a table to, and then reference parts of that table in the UDF. So, for instance my table called "Stock" may look something like this:
Name Cost Items in Stock
Teddy Bear £10 10
Lollipops 20p 1000
I have a UDF which I want to calculate the total cost of all the items left in stock (the actual example is much more complex which can't really be done without very complex formula)
Ideally the syntax of for the UDF would look something like
TOTALPRICE(Stock)
Which from what I can work out would mean the UDF would have the signature
Function TOTALPRICE(table As Range) As Variant
What I am having trouble with is how to reference the columns of the table and iterate through them. Ideally I'd like to be able to do it referencing the column headers (so something like table[Cost]).
This is very basic (no pun intended) but it will do what you describe. For larger tables it may become slow as under the hood it's going back and forth between the macro function and the worksheet, and that kind of activity adds up.
It assumes that you have one row of headers and one column of names (hence the For loop variables starting from 2).
There are all kinds of things that might be necessary - we can save those for another question or another round on this one.
Note that the function returns a "Variant", btw...
Public Function TotalPrice(table As Range) As Variant
Dim row As Long, col As Long
Dim total As Double
For row = 2 To table.Rows.Count
For col = 2 To table.Columns.Count
TotalPrice = TotalPrice + table.Cells(row, col) * table.Cells(row, col + 1)
Next
Next
End Function
Note: I dont have Excel 2007 and I am trying to write this using MSDN doc on the web.
Looks like the range will have ListColumns collection
So, the syntax could be table.ListColumns("Cost").
Does this work?

Resources