I have few formulas in a row and I want to drag them down. Formulas are complex and I don't have them in R1C1 format and I don't want to convert them into R1C1, but I would like to do something like:
Range(A2:B10).Formula = Range.(A1:B1).Formula
I know this would put the same formula into the whole range, I need a "drag effect" - so it's changes relatively to each row but without copy-pasting.
P.S. I don't want to copy-paste, as it eats more CPU, I'd like to have something
Define the range that you want to fill with the formula and use Range.FillDown.
Range("A1:B10").FillDown
Note: The first Row(s) of the range must include the original formulas
A tiny trick !:
Sub KopyFormulas()
Range("A1:B1").Copy Range("A2:B10")
End Sub
will copy the formulas downward and adjust them as well !
For single cells, you don't need to explicitly convert formulas to R1C1 format to use FormulaR1C1.
Even if you are using the standard A1 style of referencing, you can still use
Range("B2:B10").FormulaR1C1 = Range("B1").FormulaR1C1
And this will have the effect of copying down the formula in B1. It doesn't change the default format -- they will still display in the A1 format.
There does seem to be an issue with doing this with a block of two or more cells. You could do it column by column (in a loop if desired):
Range("A2:A10").FormulaR1C1 = Range("A1").FormulaR1C1
Range("B2:B10").FormulaR1C1 = Range("B1").FormulaR1C1
Whether or not this is worth the hassle (compared to the simple .FillDown) is another question. You could time it.
By the way -- I wouldn't think that .FillDown is particularly inefficient. Did you do the usual optimizations of turning off of screen-updating, setting calculation to manual, etc.?
Related
I have Terz-spectra data from acoustic measurements and I want to calculate the overall level. The values for each Terz-band are in decibel. Therefor the calculation formula is a bit lengthy. It would be L_overall=10*log10(10^(L_a/10)+10^(L_b/10)+10^(L_c/10)+10^(L_d/10)...).
As there are many frequencies, I don't want to write the whole formula by hand. I also don't want to use another column to do the inner calculation (10^(x/10)) before doing the outer calculation (10*log10(x+y+z+...)). So I wonder if there is a function in Excel that allows to apply a calculation on each cell like there is in Matlab for instance (cellfun, arrayfun).
I hope to end up with something similar like L_overall=10*log10(10^(B10:B80/10) which would allow me to do all the calculation in simply one cell.
Addition:
I have forgotten to say that I want the terz-data unaltered. I don't want to change that as I have to use it to plot that spectrum. So ideally I want all the work done in only one cell. I could do that by the lengthy formula, but it would take quite some time to type that for all frequencies.
Of course I could simply use another column and do the math there but that seems also inconvenient.
Actually the formula would be something like this:
=10*LOG(SUM(INDEX(10^(B10:B80/10),)),10)
Or this:
=10*LOG(SUMPRODUCT(10^(B10:B80/10)),10)
It's a bit clunky, but you could do 10^(L_a/10) for one cell, then click and drag the lower right corner to make that run for all cells.
Then create another cell which takes 10*log10 of the SUM of those cells.
If your goal is only to insert a specific formula in a bunch of cells you could use this:
For Each rCell In Application.Selection
rCell.Formula = "=10*log10(10^(L_a/10)+10^(L_b/10)+10^(L_c/10)+10^(L_d/10)...)"
Next rCell
Simply select all the cells in which you want to insert the formula and then run the sub. Make sure your formula is valid.
It's recommended to use =MATCH() in it's own cell and then use INDEX to refer to that cell. This makes sense, why redo the MATCH() formula over and over when it's the same result?
I want to do the same thing with the OFFSET() formula. I'm working with large tables and I understand that keeping your ranges small is the key to optimization. So, using OFFSET to figure out how big of a range i want to use has been extremely beneficial. However, sometimes I might have an IF statement that checks out several COUNTIFS that require the same range. In these cells I am forced to use the OFFSET to determine the exact same range, over and over... wouldn't it be better to simply do the same thing as INDEX/MATCH?
Unfortunately I don't think excel can output the range itself... I notice in the formula auditor that it will reveal the resulting range--i need that literal range in a cell so A1 might say "$B$2:$B$342".
Probably not possible, but thought I'd ask!
Thanks
You can try to use the 'CELL()' formula. This formula can return the 'address' of a referenced cell. See formula below:
=CELL("address",B1)&":"&CELL("address",B10)
Results should be: $B$1:$B$10
Put the above formula in cell 'A1' and see if this helps you at all. You will probably need to tweak it a bit to get the exact results you're looking for (for example, you may need to 'nest' your offset() formula within the cell() formula).
Best of luck!
Is it possible to prevent calculations happening to a single cell in Excel sheet? Let's say I have 1001 cells that are very fast to calculate, but 1 cell slows sheet down, is it possible to disable calculations for that 1 cell only?
What I'm NOT trying to do:
Disabling all of cell calculation programically
Calculating specific cells programically while global calculation is set to manual
Use Excel's =IF() function. It is set up to "short-circuit" -- it only evaluates the second parameter if the first parameter is true, oppositely for the third parameter.
So, if the cell is C1, and the cell's formula is currently
=LOOKUP(2,1/(A1:A100000=666),B1:B100000)
and you want it to only be calculated when D1 is true, use
=IF(D1,LOOKUP(2,1/(A1:A100000=666),B1:B100000),C1)
Notice it's a circular reference -- it's how you keep the value the same when D1 is false. Turn on iteration if you want to get rid of the warning message.
Another way is to use one of the third-party Add-Ins out there that lets you store a global variable off-sheet and then retrieve it, which would use syntax like this:
=IF(D1,SetGlobal("C1StoredCalculation",LOOKUP(2,1/(A1:A100000=666),B1:B100000)),GetGlobal("C1StoredCalculation"))
SetGlobal() and GetGlobal() can also be written in VBA, though they'll be a tiny bit slower than an XLL, and they'll lose the value if you reset your VBA project.
Excel does not have a method to disable calculation for a single cell.
You could move the slow formula to a separate sheet and use worksheet.enablecalculation to disable calculation for that sheet.
Or you could store the formula somewhere as text, store the result as a value in the cell, then restore the formula when you want to calculate it.
You can use a replacement UDF and take advantage of a lack of volatility.
Say we have a formula like:
=LOOKUP(2,1/(A1:A100000=666),B1:B100000)
Excel will re-calculate this if any cell in cols A or B change, but the UDF
Public Function myudf(r As Range) As Variant
myudf = Evaluate("LOOKUP(2,1/(A1:A100000=666),B1:B100000)")
End Function
will only be re-calculated when its argument changes. So pick a cell and enter:
=myudf(Z100)
make any changes you want to cells in cols A or B and myudf will remain un-re-calculated until you change Z100
You can use the same tiny trick to make "quasi-volatile" versions of =TODAY() or =NOW() for =RAND()
I don't think this can be done. You can turn off automatic calculation in entire workbooks (as you mentioned), but I don't think there is a way to do this on an individual cell.
Can't believe I don't know this, but is there a way to avoid repeating a formula in an if statement if the logical test is dependent on it?
i.e.
=IF((SUMIFS formula)=0,"",SUMIFs formula)
I want to replace that SUMIFS function in the false scenario with something short that will tell it to just programmatically repeat the formula it originally tested for. Repeating the formula twice has to have detrimental effects on processing speed. Negligible, maybe, but want to go for best-practices here. Thanks.
You can force an error like #DIV/0! and then use IFERROR, e.g.
=IFERROR(1/(1/SUMIFS_formula),"")
You can assign a Name to a formula and use the Name..............See:
Assigning a name to a formula
Relevant excerpt -
For example, let's suppose we frequently use a formula like:
=SUM(A1:A100)-SUM(B1:B100) and this resides in A101 and is copied across many columns on row 101. It would be better in this case to
create a custom formula that does this in each cell on row 101. Here
is how;
1) Select cell A101 (this is vital).
2) Go to Insert>Name>Define and
in the "Names in workbook" box type: SalesLessCosts
3) Now click in
the "Refers to" box and type: =SUM(A1:A100)-SUM(B1:B100) then click
Add.
Now you can replace the formula in cell A101 with: =SalesLessCosts.
You can also copy this across row 101 and it will change its relative
references just as the formula =SUM(A1:A100)-SUM(B1:B100) would. The
reason it does this is all down to the fact we selected A101 before
going to Insert>Name>Define and used relative references in
=SUM(A1:A100)-SUM(B1:B100) when we added it to the "Refers to" box.
If all you need to do is hide zeroes, there is an easy way:
Select all cells where you wish to hide zeroes
Go into Custom Number Formatting
Set format to "General;General;"
The custom formatting has a structure of [positive numbers];[negative numbers];[zeroes]
By making the last part blank you are effectively hiding zeroes, but showing everything else.
The advantage over conditional formatting is that you can use this on any background.
A neat trick which I sometimes use is to hide the cell value completely by using a custom format of ";;;". This way you can put images inside the cells, like the conditional formatting ones, and not see the value at all.
Try using the SUBSTITUTE function like this :
=SUBSTITUTE( VLOOKUP( H4; $D$5:$E$8; 2; 0 ); $H$1; $I$1 )
Here is an example:
Here the formula I don't want to repeat twice is the VLOOKUP function.
The result of VLOOKUP is a string found in another table (ex : "Green").
I want to check if that string matches a specific string value in $H$1 (here, "Yellow").
If it does, SUBSTITUTE replaces it with$I$1 (the error string you want. Here, "FORBIDDEN").
If it doesn't, it displays the VLOOKUP result string (the normal authorized output, like "Green").
This is useful for me because my actual formula is quite long, so I don't want to write it twice.
I also dont want to use two different cells, because I'm already applying this formula on 10 columns, meaning I should add an extra 10 columns to make it work.
In some scenarios, MAX() or MIN() can do a wonderful job.
E.g., something like this:
=IF(SUMIFSformula>0,SUMIFSformula, 0)
Can be shortened to this:
=MAX(0,SUMIFSformula)
The LET formula can be used for this exact scenario. You can define the formula as a variable and then within that same cell you can reference the variable in your formula.
The LET formula format looks like this:
=LET(name,name_value,calculation)
SUMIFS Example
Here's how it would work with your SUMIF example so that you don't have to repeat the formula:
In this screenshot we have an array A1:B7. We want to sum the values (Col B) if the name in ColA is "apple".
For this we have a standard SUMIFS formula of
=SUMIFS(B1:B7,A1:A7,"apple")
The formula is showing in E2. The result is shown in E3.
To put this into the IF statement without having to repeat the formula we can use LET as shown in the screenshot.
We create a variable with the SUMIFS formula as the value of that variable. We then write our IF statement using the variable name instead of rewriting the formula multiple times.
=LET(name,name_value,calculation)
Variable name: sumapples
Variable value: SUMIFS(B1:B7,A1:A7,"apple")
Calculation: IF(sumapples=0,"",sumapples)
Put together in the LET function it looks like this:
=LET(sumapples,SUMIFS(B1:B7,A1:B7,"apple"),IF(sumapples=0,"",sumapples))
This LET function can be used in any Excel formula, and is very useful for shortening long formulas that have repetition.
Optional: Extra complexity
If you want to you can get extra complicated by naming multiple variables.
=LET(name,name_value,name2,name_value2,calculation)
Since Excel 2007, the IFERROR statement does what the OP asked. From the help file:
Description:
Returns a value you specify if a formula evaluates to an error; otherwise, returns the result of the formula. [italics mine]
Syntax:
IFERROR(value, value_if_error)
I've since realised that this was already answered by #barry houdini above.
Here is a hack - depending on whether you are just interested in the displayed value, or whether you need to use the value in another formula:
Put your SUMIF formula in the cell (without the IF part)
Create a conditional formatting rule which sets the font color to the background color when the cell value is 0
And hey presto, you get the desired result.
As I said - it's a hack, but it does prevent the double evaluation.
There is no "clean" solution that I am aware of.
I'm trying to do conditional formatting so that the cell color will change if the value is different from the value in the cell left of it (each column is a month, in each row are the expenses on certain object. I want to monitor easily changes in prices over months.)
I can do it per cell and format-drag it, but I would like a general formula to apply to the whole worksheet.
=OFFSET(INDIRECT(ADDRESS(ROW(), COLUMN())),0,-1)
The shortest most compatible version is:
=INDIRECT("RC[-1]",0)
"RC[-1]" means one column to the left. "R[1]C[-1]" is bottom-left.
The second parameter 0 means that the first parameter is interpreted using R1C1 notation.
The other options:
=OFFSET(INDIRECT(ADDRESS(ROW(), COLUMN())),0,-1)
Too long in my opinion. But useful if the relative value is dynamic/derived from another cell. e.g.:
=OFFSET(INDIRECT(ADDRESS(ROW(), COLUMN())),0, A1)
The most simple option:
= RC[-1]
has the disadvantage that you need to turn on R1C1 notation using options, which is a no-go when other people have to use the excel.
When creating your conditional formatting, set the range to which it applies to what you want (the whole sheet), then enter a relative formula (remove the $ signs) as if you were only formatting the upper-left corner.
Excel will properly apply the formatting to the rest of the cells accordingly.
In this example, starting in B1, the left cell would be A1. Just use that--no advanced formula required.
If you're looking for something more advanced, you can play around with column(), row(), and indirect(...).
If you change your cell reference to use R1C1 notation (Tools|Options, General tab), then you can use a simple notation and paste it into any cell.
Now your formula is simply:
=RC[-1]
Instead of writing the very long:
=OFFSET(INDIRECT(ADDRESS(ROW(), COLUMN())),0,-1)
You can simply write:
=OFFSET(*Name of your Cell*,0,-1)
Thus for example you can write into Cell B2:
=OFFSET(B2,0,-1)
to reference to cell B1
Still thanks Jason Young!! I would have never come up with this solution without your answer!
fill the A1 cell, with the following formula :
=IF(COLUMN(A1)=1;"";OFFSET(A20;0;-1))&"1"
Then autoextend to right, you get
1| A | B | C | ect ect
2| 1| 11| 111| ect ect
If offset is outside the range of the available cell, you get the #REF! error.
Hope you enjoy.
Even simpler:
=indirect(address(row(), column() - 1))
OFFSET returns a reference relative to the current reference, so if indirect returns the correct reference, you don't need it.
Why not just use:
=ADDRESS(ROW(),COLUMN()-1)
You could use a VBA script that changes the conditional formatting of a selection (you might have to adjust the condition & formatting accordingly):
For Each i In Selection
i.FormatConditions.Delete
i.FormatConditions.Add Type:=xlCellValue, Operator:=xlLess, Formula1:="=" & i.Offset(0, -1).Address
With i.FormatConditions(1).Font
.Bold = True
End With
Next i
I stumbled upon this thread because I wanted to always reference the "cell to the left" but CRUCIALLY in a non-volatile way (no OFFSET, INDIRECT and similar disasters). Looking the web up and down, no answers. (This thread does not actually provide an answer either.) After some tinkering about I stumbled upon the most astonishing method, which I like to share with this community:
Suppose a starting value of 100 in E6. Suppose I enter a delta to this value in F5, say 5. We would then calculate the continuation value (105) in F6 = E6+F5. If you want to add another step, easy: just copy column F to column G and enter a new delta in G5.
This is what we do, periodically. Each column has a date and these dates MUST BE in chronological order (to help with MATCH etc). Every so often it happens that we forget to enter a step. Now suppose you want to insert a column between F and G (to catch up with your omission) and copy F into the new G (to repopulate the continuation formula). This is NOTHING SHORT of a total disaster. Try it - H6 will now say =F6+H5 and NOT (as we absolutely need it to) =G6+H5. (The new G6 will be correct.)
To make this work, we can obfuscate this banal calculation in the most astonishing manner F6=index($E6:F6;1;columns($E1:F1)-1)+F5. Copy right and you get G6=index($E6:G6;1;columns($E1:G1)-1)+G5.
This should never work, right? Circular reference, clearly! Try it out and be amazed. Excel seems to realize that although the INDEX range spans the cell we are recalculating, that cell itself is not addressed by the INDEX and thus DOES NOT create a circular reference.
So now I am home and dry. Insert a column between F and G and we get exactly what we need: The continuation value in the old H will refer back to the continuation value we inserted in the new G.
Make a named formula "LeftCell"
For those looking for a non-volatile answer, you can accomplish this by using the INDEX function in a named formula.
Select Cell A2
Open Name Manager (Ctrl+F3)
Click New
Name it 'LeftCell' (or whatever you prefer)
For Scope:, select Workbook
In Refers to:, enter the formula:
=INDEX(!A1:!A2, 1)
Click OK and close Name Manager
This tells Excel to always look at the value immediately to the left of the current cell, and will change dynamically as different cells are selected. If the name is used alone it provides the cell's value, but in a range it uses the reference. Credit to this answer about cell references for the idea.
I think this is the easiest answer.
Use a "Name" to reference the offset.
Say you want to sum a column (Column A) all the way to, but not including, the cell holding the summation (say Cell A100); do this:
(I assume you are using A1 referencing when creating the Name; R1C1 can subsequently be switched to)
Click anywhere in the sheet not on the top row - say Cell D9
Define a Named Range called, say "OneCellAbove", but overwrite the 'RefersTo' box with "=D8" (no quotes)
Now, in Cell A100 you can use the formula =SUM(A1:OneCellAbove)
When creating a User Defined Function, I found out that the other answers involving the functions OFFSET and INDIRECT cannot be applied.
Instead, you have to use Application.Caller to refer to the cell the User Defined Function (UDF) has been used in. In a second step, you convert the column's index to the corresponding column's name.
Finally, you are able to reference the left cell using the active worksheet's Range function.
Function my_user_defined_function(argument1, argument2)
' Way to convert a column number to its name copied from StackOverflow
' http://stackoverflow.com/a/10107264
' Answer by Siddarth Rout (http://stackoverflow.com/users/1140579/siddharth-rout)
' License (if applicable due to the small amount of code): CC BY-SA 3.0
colName = Split(Cells(, (Application.Caller(1).Column - 1)).Address, "$")(1)
rowNumber = Application.Caller(1).Row
left_cell_value = ActiveSheet.Range(colName & rowNumber).Value
' Now do something with left_cell_value
Please select the entire sheet and HOME > Styles - Conditional Formatting, New Rule..., Use a formula to determine which cells to format and Format values where this formula is true::
=A1<>XFD1
Format..., select choice of formatting, OK, OK.