I have following data in Excel:
A B C
1 Task Name Total Effort (days) %Finished
2 Task 1 5 30
3 Task 2 8 25
4 Task 3 23 18
5 Task 4 32 5
All I want to get is "=SUM(B2*C2 : B5*C5)". But Excel doesn't allow me to do this. How do I achieve my goal?
This is simple with SUMPRODUCT:
=SUMPRODUCT(B2:B5,C2:C5)
To elaborate, while #Olly's answer SUMPRODUCT(B2:B5, C2:C5) is indeed correct, however I got impression from your original post that you are a bit confused about the selectors in hand - I do believe you should study up on it before even copy-pasting any formula.
In excel formulas, if you are refering to a range of cells, you do it by declaring the range from it's starting point, to it's ending point with a colon.
So for example, the green range would be A1:A5, the blue range would be C3:E3 and the yellow range would be F5:G11
Next we have separators, these seperate individual ranges (or cells - even an individual cell is a range itself, a range with a size of 1 cell)
For example with the following range, we would select it as (A1:A2, A5, A7:A8) notice the comma (,) acting as a separator.
Now as to how =SUMPRODUCT actually works, it takes two ranges, pits them side by side. It then does multiply the first cell of the first range with the first cell of the second range and so on. In the end, it adds them all together.
That sounds a bit difficult in words. Here is an illustration
So yes, this actually means the individual values don't even have to be side by side.
Hopefully you understand now not only how your code should look like, but also why your original code didn't work! :)
Related
Suppose you have an ordered, indexed list of positive values. These positive values are interrupted by 0 values. I want to determine if a consecutive sub-array exists which is not interrupted by 0 values and whose sum exceeds a certain threshold.
Simple example:
Index, Value
0 0
1 0
2 3
3 4
4 2
5 6
6 0
7 0
8 0
9 2
10 3
11 0
In the above example, the largest consecutive sub-array not interrupted by 0 is from index 2 to index 5 inclusive, and the sum of this sub-array is 15.
Thus, for the following thresholds 20, 10 and 4, the results should be FALSE, TRUE and TRUE respectively.
Note I don't necessarily have to find the largest sub-array, I only have to know if any uninterrupted sub-array sum exceeds the defined threshold.
I suspect this problem is a variation of Kadane's algorithm, but I can't quite figure out how to adjust it.
The added complication is that I have to perform this analysis in Excel or Google Sheets, and I cannot use scripts to do it - only inbuilt formulas.
I'm not sure if this can even be done, but I would be grateful for any input.
Start with
=B2
in c2
then put
=IF(B3=0,0,B3+C2)
in C3 and copy down.
EDIT 1
If you were looking for a Google sheets solution, try something like this:
=ArrayFormula(max(sumif(A2:A,"<="&A2:A,B2:B)-vlookup(A2:A,{if(B2:B=0,A2:A),sumif(A2:A,"<="&A2:A,B2:B)},2)))
Assumes that numbers in column B start with zero: would need to add Iferror if not. It's basically an array formula implementation of #Gary's student's method.
EDIT 2
Here is the Google Sheets formula translated back into Excel. It gives you an alternative if you don't want to use Offset:
=MAX(SUMIF(A2:A13,"<="&A2:A13,B2:B13)-INDEX(SUMIF(A2:A13,"<="&A2:A13,B2:B13),N(IF({1},MATCH(A2:A13,IF(B2:B13=0,A2:A13))))))
(entered as an array formula).
Comment
Maybe the real challenge is to find a formula that works both in Excel and Google sheets because:
Vlookup doesn't work the same way in Excel
The offset/subtotal combination doesn't work in Google sheets
The index/match combination with n(if{1}... doesn't work in Google sheets.
With data in columns A and B, insure column B end with a 0. Then in C2 enter:
=IF(AND(B3=0,B2<>0),SUM(B$1:$B2)-MAX($C$1:C1),"")
and copy downwards:
Column C lists the sums of consecutive non-zeros. In another cell enter something like:
=MAX(C:C)>19
where 19 is the criteria value.
You can avoid the "helper" column by using a VBA UDF.
EDIT#1:
Use this instead:
=IF(AND(B3=0,B2<>0),SUM(B$1:$B2)-SUM($C$1:C1),"")
Thanks to #Tom Sharpe and #Gary's Student for answering the question.
While I admittedly did not specify this in the question, I would prefer to achieve the solution without a helper column because I have to do this operation on 30+ successive columns. I just didn't think it was possible in Excel.
Full credit goes to user XOR LX on the Excelforum for coming up with this solution. It has blown my mind and took me the better part of an hour to wrap my head around, but it is certainly very creative. There is no way I could have come up with it myself. Re-posting it here for the benefit of everyone who is looking into this.
Copy and paste the table from my initial question into an empty Excel sheet such that the headers appear in (A1:B1) and the values appear in (A2:B13).
Then enter this formula as an array formula (ctrl+shift+enter), which gives the max of the sums of all the uninterrupted sub-arrays:
=MAX(SUBTOTAL(9,OFFSET(B2,A2:A14,,-FREQUENCY(IF(B2:B13,A2:A13),IF(B3:B14=0,A2:A13,0))-1)))
Note the deliberate offset to include one additional row below the end of the dataset.
I have a large series of numbers that I want to convert to a 0 to 10 scale.
I used the following formula to convert the maximum value to 10 and minimum value to 0,
=IF(A1="-","0",MIN(MAX((A1-MIN(A:A))/((MAX(A:A)-MIN(A:A))/11),0),10))
However,I face some problems converting the series where maximum value should be 0 and minimum value should be 10. For example, if column A has the values,
1
4
6
7
8
then 8 should have a value of 0 and 1 should have a value of 10.
Thanks!
Just use the formula =10-B1, where B1 is the cell containing your mentioned formula.
Please note though that your formula has the following flaws:
It is wrong. If you test it with the three numbers 1,2,3 you get 5.5 for the value corresponding to 2. Obviously the correct answer should be 5. This error is caused by the number 11 that you use to divide the (MAX(A:A)-MIN(A:A)). Change it to 10 and everything will work!
It returns #DIV/0! if you have only one number in column A.
It is inefficient because it calls time-expensive functions MAX(A:A) and MIN(A:A) in each and every cell containing this formula. Since these two functions are not dependent on the formula-containing cell, consider using them only once in some other cells and subsequently modify your formula so it contains links to these external cells rather than the functions themselves.
It is hardly maintainable and/or readable. It took me a while to understand how your formula works. Consider separating it into meaningful pieces, place the pieces into separate cells and finally simply link the pieces together in some final - and much smaller - formula.
It is unnecessarily convoluted. There is a much easier formula to achieve the same thing, based on the following:
= 10*B1/C1,
where B1 contains the "distance from minimum", i.e. A1-MIN(A:A), and C1 contains the total length of your range of numbers, i.e. MAX(A:A)-MIN(A:A)
I'm new to excel but have enjoyed trying new things with the program. I'm trying to figure out if I can have one cell read something based on the standing of other cells. For example:
If g10 = 6 then h14 will read either unacceptable, acceptable, recognized or exemplary based on a the scale shown below.
0-1 unacceptable
2-4 acceptable
5-7 recognized
8-9 exemplary
Is this possible?
There are a dozen ways to do any one thing in Excel and this is no different. I'll show you two.
First you can do this with a bunch of IF statements
=IF(G10<=2,"Unacceptable",IF(G10<=4,"Acceptable",IF(G10<=7,"Recognized",IF(G10<=9,"Exemplary","Too Good"))))
You can see this is pretty good but it means you need to rewrite your formula if anything changes in your scale.
The other way is to use VLookups.
I put these values in the range A1:B10
0 Unaceptable
1 Unaceptable
2 Acceptable
3 Acceptable
4 Acceptable
5 Recognized
6 Recognized
7 Recognized
8 Exemplary
9 Exemplary
Then used this formula for the lookup
=VLOOKUP(G10,A1:B10,2,FALSE)
Where
=VLOOKUP(D16 <~~ The value to use to look up
,A1:B10 <~~ The range in which you're doing the lookup. The lookup is always performed on the left most column. Any other columns included in the range are available to be return values.
,2 <~~ Column from range A1:B10 to return from the Vlookup function
,FALSE <~~ Whether or not to do approximate matching. You more than likely always want exact matching so this will usually be false
)
If you will be using this in more than one cell and/or are copy/pasting it around you can lock in the lookup range using $. i.e. =VLOOKUP(G10,$A$1:$B$10,2,FALSE) These will not be relative references if you use the $ sign. You can put this in by hitting F4
One step better than this is to use named ranges though. This means while you have our grading scale highlighted in A1:B10 you go to that text box to the left of the formula bar and type MyGradingScale and they now you can refer to that range by name.
=VLOOKUP(G10,MyGradingScale,2,FALSE)
You can then use this formula in lots of places and upgate it in one place. Go to Formulas>Name Manager on the ribbon to change the reference.
This is fairly simple, depending on what version of Excel you're using.
A simple, IF(AND()) formula should work here
Try:
=IF(AND(A1>=0,A1<=1), "Unacceptable", NEXT TEST HERE)
That should get you started, just use nested IF(AND()) statements.
(Alternate title: Why on earth doesn't Excel support user-defined formulas with parameters without resorting to VB and the problems that entails?).
[ Updated to clarify my question ]
In excel when you define a table it will tend to automatically replicate a formula in a column. This is very much like "fill down".
But ... what if you need exceptions to the rule?
In the tables I'm building to do some calculations the first row tends to be "special" in some way. So, I want the auto-fill down, but just not on the first row, or not on cells marked as custom. The Excel docs mention exceptions in computed columns but only in reference to finding them and eliminating them.
For example, first row is computing the initial value
The all the remaining rows compute some incremental change.
A trivial example - a table of 1 column and 4 rows:
A
1 Number
2 =42
3 =A2+1
4 =A3+1
The first formula must be different than the rest.
This creates a simple numbered list with A2=42, A3=43, A4=44.
But now, say I'd like to change it to be incremented by 2 instead of 1.
If I edit A3 to be "A2+2", Excel changes the table to be:
A
1 Number
2 =A1+2
3 =A2+2
4 =A3+2
Which of course is busted -- it should allow A2 to continue to be a special case.
Isn't this (exceptions - particularly in the first row of a table) an incredibly common requirement?
If you have the data formatted as a table you can use table formulas (eg [#ABC]) instead of A1 format (eg A1, $C2 etc). But there are 2 tricks to account for.
Firstly there is no table formula syntax for the previous row, instead excel will default back to A1 format, but you can use the offset formula to move you current cell to the previous row as shown below. However in this case it will return an # value error since I cant +1 to "ABC".
ABC
1 =OFFSET([#ABC],-1,0)+1
2 =OFFSET([#ABC],-1,0)+1
3 =OFFSET([#ABC],-1,0)+1
4 ....
So the second trick is to use a if statement to intialise the value, buy checking if the previous row value = heading value. If the same use the initial value else add the increment. Note assumes table is named Table1
ABC
1 =IF(OFFSET([#ABC],-1,0)=Table1[[#Headers],[ABC]],42,OFFSET([#ABC],-1,0)+1)
2 =IF(OFFSET([#ABC],-1,0)=Table1[[#Headers],[ABC]],42,OFFSET([#ABC],-1,0)+1)
3 =IF(OFFSET([#ABC],-1,0)=Table1[[#Headers],[ABC]],42,OFFSET([#ABC],-1,0)+1)
4 ....
Note you can set the initial value to be a cell outside the table to define the initial value (in say $A$1) and increment (in say $A$2) as below
ABC
1 =IF(OFFSET([#ABC],-1,0)=Table1[[#Headers],[ABC]],$A$1,OFFSET([#ABC],-1,0)+$A$2)
2 =IF(OFFSET([#ABC],-1,0)=Table1[[#Headers],[ABC]],$A$1,OFFSET([#ABC],-1,0)+$A$2)
3 =IF(OFFSET([#ABC],-1,0)=Table1[[#Headers],[ABC]],$A$1,OFFSET([#ABC],-1,0)+$A$2)
4 ....
I use this IF OFFSET combination all the time for iterating and looping in tables.
If you have alot of columns that need to determine if they are the first row you can have one column test if first row and the rest can work with a simpler if. eg ABC will give true for first row false for others, then DEF with increment the initial value
ABC DEF
1 =OFFSET([#ABC],-1,0)=Table1[[#Headers],[ABC]] =IF([#ABC],$A$1,OFFSET([#DEF],-1,0)+$A$2)
2 =OFFSET([#ABC],-1,0)=Table1[[#Headers],[ABC]] =IF([#ABC],$A$1,OFFSET([#DEF],-1,0)+$A$2)
3 =OFFSET([#ABC],-1,0)=Table1[[#Headers],[ABC]] =IF([#ABC],$A$1,OFFSET([#DEF],-1,0)+$A$2)
4 ....
Hope that helps
I don't know if you are looking for something as simple as locking down a formula. You can do that by highlighting the part of the formula you do not want to change and then hitting F4. This will absolute this section of the formila, using a $ to indicate it, and will not change as you copy/paste it down the table.
Alternately, you may be able to use Defined Names. These you can set up in the Data tab and basically assigns something to a name or variable you can then put into your formulas. These can be as simple as an easy reference for a cell on another sheet to incredibly complex multi-sheet formals.
Normally, to handle "exceptional" formula in the first row of a table consiting of several columns, you simply enter it there manually, and fill only the lines below. But if you have more "exceptional" cases scattered around, you will need another column with 0/1 values indicating where the exceptins are. And then you use if(condition, formula_if_true, formula_if_false) everywhere.
A B
Number Exceptional?
1 if(C1,42,A1+1) 0
2 if(C2,42,A2+1) 1
3 if(C3,42,A3+1) 0
As much as I love Excel, and as much as it is the best product of whole MS, it is still a weak tool. FYI, you can quiclky learn modern and poweful scripting languages, such as Ruby, here, and never be bothered by spreadsheet idiosyncrasies again.
How do I use conditional formatting to format only the last cell in each column with a minimum value ?
This implies a non-VBA solution.
I have tried using this formula, but it stops after first match (5 is formatted):
AND(A2>=5,COUNTIF($A$2:A2,">=5")=1)
Using this data, only 9 should be formatted.
Data:
1
2
3
4
5 <-- actual result
6
7
8
9 <-- expected result
UPDATE:
This formula seems to do the trick, but only works when the cell values in the range are numeric, which mine are, and only in 1 column. Range must match format area.
Note: I found the "INDEX..E+307" part somewhere else, but lost the URL so cant give credit.
AND(A2>=5,A2=INDEX($A$2:A10,MATCH(9.99999999999999E+307,$A$2:A10)))
A multi-column supported formula is now needed. Using OFFSET might be the way to go..
I'm reading the problem as this:
We want to highlight the last cell in the column, but only when the cells in that column contain at least one sufficiently large value.
Assuming data starts in A1, I came up with this:
=AND(COUNTIF(OFFSET(A$1,,,COUNT(A:A),1),">=5")>0,ROW()=COUNT(A:A))
There are some assumptions there: like we can say that the number of non-empty values can be counted by COUNTA(), or that data starts in row 1 so that we can find the last row with ROW()=COUNT(A:A). But hopefully you get the idea...
If you are in fact looking for the greatest value, not the last one, then this be a starting point:
AND(A2>=5,A2=MAX($A$2:A10))
That should work to locate the highest value across multiple columns as well. If your table can grow over time then you should look at defining the range with an OFFSET() formula.