I have a range of value (say H6:H20) containing values "g","y" or "r".
In order to count each status and use that as the source of a donut chart, I made a range of 3 cells calculating =COUNTIF($H$6:$H$20,"Green") etc...
Then I tried to be more elegant and create a single array formula returning the count for each letter, that I could eventually use as the source of my chart, without having intermediry calculation range. But I can't get this working.
Input:
g
r
y
g
g
r
g
g
y
Expected output (with a single array formula):
5
2
2
My try: =COUNTIF({"g","y","r"},$H$6:$H$20) -> error
Other try: =SUMPRODUCT(1*$H$6:$H$20={"g","y","r"}) -> error
(both entered in a 3 cells range with Ctrl+Shift+Enter, of course)
What is the right formula ?
You don't need an array formula, though you do need to store that formula as a Defined Name within Name Manager, e.g.:
Name: Series_Values
Refers to: =COUNTIF(Sheet1!$H$6:$H$20,{"g","y","r"})
Change the sheet name (Sheet1 here) as required.
You can then add a series to a chart with the following syntax for the Series values entry:
='Sheet1'!Series_Values
Again, amend the sheet name as required, though be sure to retain the exclamation mark and apostrophes (the latter are not strictly necessary if the worksheet name contains no spacing, though in any case it is good practice).
Excel will actually amend this to:
=Book1!Series_Values
(where Book1 is the assumed workbook name), though this is not important here.
Regards
That's what FREQUENCY function is for. Select 3 cells and CTRL+SHIFT+ENTER following formula:
=FREQUENCY(MATCH($H$6:$H$20,{"g","y","r"},0),MATCH($H$6:$H$20,{"g","y","r"},0))
Assuming this isn't dynamic, and you have a definite amount of rows, you can use the following. Let's say you're putting this formula in row 20:
=COUNTIF($A$1:$A$9,INDEX({"g","r","y"},ABS(20-(ROW()+1))))
and drag down.
Edit: If you want in the same cell, just combine COUNTIF()?
=COUNTIF($A$1:$A$9,"g")&","&COUNTIF($A$1:$A$9,"r")&","&COUNTIF($A$1:$A$9,"y")
=IF({"g","y","r"}="g",COUNTIF($H$6:$H$20,"g"),IF({"g","y","r"}="y",COUNTIF($H$6:$H$20,"y"),IF({"g","y","r"}="r",COUNTIF($H$6:$H$20,"r"))))
long solution as I don't have time to make a more elegant one. You can see the array object with F9 in the formula bar.
Related
I am an occasional Excel user and stuck how to create a dynamic range.
After looking up a text in a table, how can I calculate the range next to this cell, up to the next empty row? Not using VBA.
Thanks for your help.
In H4, formula copied down :
=IFERROR(INDEX(INDEX(C:C,MATCH(F4,A:A,0)):C$1000,MATCH(G4,INDEX(B:B,MATCH(F4,A:A,0)):B$1000,0)),"")
Should you want a dynamic range,
Change C$1000 to INDEX(C:C,MATCH(9.9E+307,B:B)
and
Change B$1000 to INDEX(B:B,MATCH(9.9E+307,B:B))
Then
The H4 copied down formula become :
=IFERROR(INDEX(INDEX(C:C,MATCH(F4,A:A,0)):INDEX(C:C,MATCH(9.9E+307,B:B)),MATCH(G4,INDEX(B:B,MATCH(F4,A:A,0)):INDEX(B:B,MATCH(9.9E+307,B:B)),0)),"")
Edit :
As per Ron Rosenfeld's comment, "should B11 change to 24 and G4 change to 24"
The "Source Table" set up in Excel Table type for dynamic range growing purpose
and
The H4 formula change to :
=IFERROR(LOOKUP(9^9,Table1[price]/(LOOKUP(ROW(Table1[texture]),ROW(Table1[texture])/(Table1[texture]<>""),Table1[texture])=F4)/(Table1[length]=G4)),"")
Combining the Index() and Match() functions usually works well when using two conditions. However, you will need to fill out the entire column A with the "texture" list in order for the below formula to work.
=INDEX(<P1>, MATCH(TRUE, (<T1>=<T2>) + (<L1>=<L2>) > 1,0))
Where <P1> is your entire price column (ex. C2:C15)
Where <T1> is your entire texture column (ex. A2:A15)
Where <T2> is your texture lookup value cell
Where <L1> is your entire length column (ex. B2:B15)
Where <L2> is your length lookup value cell
Let's say that you input your texture value into cell F3, and your length value into cell F4. With the remaining columns remaining as they are in your image, you would use the following formula:
=INDEX(C2:C15, MATCH(TRUE, (A2:A15=F3) + (B2:B15=F4) > 1,0))
Now last time I had to use Index/Match I thought I had to place the formula into an array. However, the above seems to work without it.
If you notice that it's not working as expected, you can place into an array formula by clicking the cell that contains the formula, then clicking the formula box at the top. While in the formula box, simultaneously press Ctrl + Shift + Return. This should then place curly brackets around your entire formula if done properly, as such:
If you have O365 with the SEQUENCE function, you can use, for price:
=IF(G4="","",VLOOKUP(G4,INDEX($B:$C,SEQUENCE(MATCH(TRUE,ISBLANK(INDEX($B:$B,MATCH(F4,$A:$A,0)):INDEX(B:B,ROWS(B:B)-MATCH(F4,$A:$A,0))),0)-1,,MATCH(F4,$A:$A,0)),{1,2}),2,FALSE))
explanation:
get starting row:
MATCH(F4,$A:$A,0)
ending row will be the first blank row after the starting row:
MATCH(TRUE,ISBLANK(INDEX($B:$B,MATCH(F4,$A:$A,0)):INDEX(B:B,ROWS(B:B)-MATCH(F4,$A:$A,0))),0)
Construct the relevant array:
INDEX($B:$C,SEQUENCE(MATCH(TRUE,ISBLANK(INDEX($B:$B,MATCH(F4,$A:$A,0)):INDEX(B:B,ROWS(B:B)-MATCH(F4,$A:$A,0))),0)-1,,MATCH(F4,$A:$A,0)),{1,2})
The above might reduce (with wavy) to:
index(b:c,{9,10,11},{1,2}
Then it's just a matter of applying the VLOOKUP
A more understandable, but longer with more operations, formula available in O365 makes use of LET. The advantage is that one can use names which indicate what each section of the formula does.
For example:
=IF(G4="","",LET(startRow,MATCH(F4,$A:$A,0),numRows,MATCH(TRUE,ISBLANK(INDEX($B:$B,startRow):INDEX($B:$B,ROWS($B:$B)-startRow)),0)-1,
arr,INDEX($B:$C,SEQUENCE(numRows,,startRow),{1,2}),price,XLOOKUP(G4,INDEX(arr,0,1),INDEX(arr,0,2)),price))
Or, using VLOOKUP
=IF(G4="","",VLOOKUP(G4,LET(startRow,MATCH(F4,$A:$A,0),numRows,MATCH(TRUE,ISBLANK(INDEX($B:$B,startRow):INDEX($B:$B,ROWS($B:$B)-startRow)),0)-1,arr,INDEX($B:$C,SEQUENCE(numRows,,startRow),{1,2}),arr),2,FALSE))
Finally, for earlier versions of Excel, you can use this whopper where we replace the SEQUENCE function with a construct like: ROW(INDEX(A:A,firstRow):INDEX(A:A,lastRow))
=IF(G4="","",VLOOKUP(G4,INDEX($B:$C,ROW(INDEX($A:$A,MATCH(F4,$A:$A,0)):INDEX($A:$A,MATCH(F4,$A:$A,0)+MATCH(TRUE,INDEX($B:$B,MATCH(F4,$A:$A,0)):INDEX($B:$B,ROWS($B:$B))="",0)-2)),{1,2}),2,FALSE))
How do I find either the cell address or preferably the row and column of the value 119, or any other number in the table below?
The table does not contain row or column titles, only the numbers as shown.
I am looking for a worksheet solution (formula) and not a VBA solution.
An Array Formula
This is an array formula and it has to be entered with control shift enter i.e. hold control shift and then press enter.
=MAX(IF(A1:J34=119,ROW(A1:J34)-ROW(A1)+1))
Remarks:
The value is searched by column i.e. A1, A2, ... B1, B2 ... i.e. if you had another 119 in cell D1 the result would still be 2, and if you had a 119 in cell c1 then the result would be
1.
For a column version just replace ROW with COLUMN:
=MAX(IF(A1:J34=119,COLUMN(A1:J34)-COLUMN(A1)+1))
Well, clunky and you can expand it, but it does work:
Row is separate to column but you could put them together in one cell, does depend on how you want to use the results, but you did not specify that so I have done this...
You could use a choose() function or a lookup table with vlookup() to change the column result to a letter...
Please try:
=MOD((K1-50),34)+1&" | "&1+(INT((K1-50)/34))
where K1 is your selected value.
Returns R | C. (Data in A1:J34 is not required.)
Below is a general purpose answer based on VBasic2008's answer.
I modified the formulas to utilize defined names so that the cell references do not have to be hard coded in the formulas. This way both the data table and row / column formulas can be relocated to anywhere on the spreadsheet. It works for both numerical AND text based data.
I also included the =ADDRESS() function to return the absolute reference of the look up value.
For illustration purposes, a step by step example for Data Set 1 is shown replacing the hard coded cell references with defined names.
The Data Set 2 section is the simplified version just using one defined for each the row and column look up value.
You can download an example spreadsheet here: Look_Up_a_Value_in_a_Table.xls
Thanks to all of you: Solar Mike, VBasic2008, and pnuts
Click on the image to enlarge.
I am going crazy over this. It seems so simple yet I can't figure this out. I have two worksheets. First worksheet is my data. Second is like an answer key. Upon checking checking, A1:B1 in Sheet 1 is a match with the conditions in Row 52 in SHEET 2, therefore, the value in Column C is "MGC". What is the formula that will perform this function? It's really hard to explain without the data so I pasted a link of the sample spreadsheet. Thank you so much in advance.
sample spreadsheet here. https://docs.google.com/spreadsheets/d/1_AjuNfCdGfEM-XkqPa6W4hSIxQg4NM2Vg4c2C1pQ_vQ/edit?usp=sharing
screenshot here. (wont let me post i have no reputation)
In Sheet2, insert a column in front of Column A and put the formula in A2 =C2&D2.
Then in Sheet1, Cell C2 the formula =vlookup(A2&B2,Sheet2!A:B,2,0).
the first make a concatenated key to lookup, then the second looks up that key.
How about a index(match())? If I've understood correctly you need to match across both the A and B column in sheet one, checking for the relevant values in B and C on sheet 2 to retrun worksheet 2 column a to worksheet 1 column c.
third version try:
=INDEX(Sheet2!$C$1:$C$360,MATCH(Sheet1!A1&Sheet1!B1,Sheet2!$B$1:$B$360&Sheet2!$C$1:$C$360,0))
Basically what this does is use concatenation, the & operator, to specify you are looking for "Criteria A" & "Criteria B" in sheet 1, which makes the string "Criteria A Criteria B", which is supplied in the first part of the match function.
In the second it then says match this against all of my variables in sheet 2 in the same way with concantenation.
The final part of match function (0) specifies you want an 'exact' match
It then supplied this as a reference to the index function, which then finds the row intersecting with the value you want, and returns that.
As noted here https://support.microsoft.com/en-us/kb/59482 this is an array formula, so it behaves differently, and must be input differently. https://support.office.com/en-za/article/Guidelines-and-examples-of-array-formulas-7d94a64e-3ff3-4686-9372-ecfd5caa57c7
There are (at least) 2 ways you could do this without VBA.
USING A SORTED LIST
The first relies on the assumption that your data can be re-sorted, so that everything "Unreported" is in the top, and everything "reported" is together below that (or vice versa). Assuming that this is the case (and it appears to already be sorted like this),we will use the function OFFSET to create a new range which shows only the values that align with either being "Unreported" or "Reported".
Offset takes a given reference to a point on a sheet, and then moves down/up & left/right to see what reference you want to return. Then, it returns a range of cells of a given height, and a given width. Here, we will want to start on Sheet2 at the top left, moving down until we find the term "Unreported" or "Reported". Once that term is found, we will want to move one column to the right (to pull column B from sheet 2), and then have a 'height' of as many rows as there are "unreported" or "reported" cells. This will look as follows in A1 on sheet 1, copied down:
=OFFSET(Sheet2!$A$1,MATCH(A1,Sheet2!A:A,0)-1,1,COUNTIF(Sheet2!A:A,A1),1)
This says: First, start at cell A1 on sheet2. Then find the term in A1 (either "unreported" or "reported", on sheet2!A:A (we subtract 1 because OFFSET starts at A1 - so if your data starts at A1 we need to actually stay at "0". If you have headers on sheet2, you will not need this -1). Then, move 1 column to the right. Go down the rows for as many times as Sheet2 column A has the term found in Sheet1 A1. Stay 1 column wide. Together, this will leave you with a single range on sheet2, showing column B for the entire length that column A matches your term in sheet1 A1.
Now we need to take that OFFSET, and use it to find out when the term in Sheet1 B1 is matched in Sheet2 column B. This will work as follows:
=MATCH(B1,[FORMULA ABOVE],0)
This shows the number of rows down, starting at the special OFFSET array created above, that the term from B1 is matched in column B from sheet2. To use this information to pull the result from column C on sheet 2, we can use the INDEX function, like so:
=INDEX([FORMULA ABOVE],MATCH(B1,[FORMULA ABOVE],0))
Because this would be fairly convoluted to have in a single cell, we can simplify this by using VLOOKUP, which will only require the OFFSET function to be entered a single time. This will work as follows:
=VLOOKUP(B1,[FORMULA ABOVE],2,0)
This takes the OFFSET formula above, finds the matching term in B1, and moves to the 2nd column to get the value from column C in sheet2. Because we are going to use VLOOKUP, the offset formula above will need to be adjusted to provide 2 columns of data instead of 1. Together, this will look as follows:
FINAL FORMULA FOR SHEET1, C1 & COPIED DOWN
=VLOOKUP(B1,OFFSET(Sheet2!$A$1,MATCH(A1,Sheet2!A:A,0)-1,1,COUNTIF(Sheet2!A:A,A1),2),2,0)
OPTION USING ARRAY FORMULAS
The above method will only work if your data is sorted so that the REPORTED and UNREPORTED rows are grouped together. If they cannot be sorted, you can use an ARRAY FORMULA, which essentially takes a formula which would normal apply to a single cell, and runs it over an entire range of cells. It returns an array of results, which must be reduced down to a single value. A basic array formula looks like this [assume for this example that A1 = 1, A2 = 2...A5 = 5]:
=IF(A1:A5>3,A1:A5,"")
Confirm this (and all array functions) by pressing CTRL + SHIFT + ENTER, instead of just ENTER. This looks at each cell from A1:A5, and if the value is bigger than 3, it gives the number from that cell - otherwise, it returns "". In this case, the result would be the array {"";"";"";4;5}. To get the single total of 9, wrap that in a SUM function:
=SUM(IF(A1:A5>3,A1:A5,""))
In your case, we will want to use an array formula to see what row in Sheet2 matches A1 from Sheet1, and B1 from Sheet1. This will look like this:
=IF(Sheet2!$A$1:A$100=A1,IF(Sheet2!$B$1:$B$100,ROW($B$1:$B$100),""),"")
This checks which rows in column A from sheet 2 match A1. For those that do, it then checks which rows in column B from sheet 2 match B1. For those, it pulls the row number from that match. Everything else returns "". Assuming no duplicates, there should only 1 row number which gets returned. To pull that number from the array of results, wrap the whole thing in a MATCH function. Now that you have the row number, you can use an INDEX function to pull the result in Column C with that row, like this:
FINAL ARRAY FORMULA METHOD
=INDEX($C$1:$C$100,MAX(IF(Sheet2!$A$1:A$100=A1,IF(Sheet2!$B$1:$B$100,ROW(Sheet2!$B$1:$B$100),""),"")))
Remember to confirm with CTRL + SHIFT + ENTER instead of just ENTER, when you type this formula. Note that I didn't refer to all of Sheet2!A:A, because array formulas run very slowly over large ranges.
The following formula should work without making any changes to the datasheets.
=INDEX(Sheet2!$A$1:$A$360,MATCH(Sheet1!A1,IF(Sheet2!$C$1:$C$360=Sheet1!B1,Sheet2!$B$1:$B$360),0))
Remember to save this formula as an array with CTRL+SHIFT+ENTER
Documentation on how to use INDEX and MATCH against multiple criteria can be found on Microsoft Support.
It's not clear what you want to do with the multiples that do not have corresponding matches. txed is listed as Unreported twice in Sheet1; kntyctap is listed as Unreported three times. There are only one corresponding match on Sheet2 for each of these.
Non-array Standard Formulas for multiple criteria matches
For Excel 2010 and above use this standard formula in Sheet1!C1:
=IFERROR(INDEX(Sheet2!$A$1:$A$999,AGGREGATE(15,6,ROW(1:999)/((Sheet2!$B$1:$B$999=A2)*(Sheet2!$C$1:$C$999=B1)), COUNTIFS(A$1:A1, A1, B$1:B1, B1))), "")
For version of Excel prior to 2010 use this standard formula in Sheet1!C1:
=IFERROR(INDEX(Sheet2!$A$1:$A$999, SMALL(INDEX(ROW($1:$999)+((Sheet2!$B$1:$B$999<>A1)+(Sheet2!$C$1:$C$999<>B1))*1E+99, , ), COUNTIFS(A$1:A1, A1, B$1:B1, B1))), "")
I've handled error with the IFERROR function in that latter formula. Excel 2003 and previous may have to use an IF(ISERROR(..., ...)) combination.
I currently have this:
=SUMPRODUCT(SUMIF(A:A;Index(List;;1);B:B))
Column A is a list of names, column B is a list of values for each names. The named range List has 2 columns, the first one are names and the second one are boolean values (0 or 1).
My formula actually works to return the sum of every column B values of its corresponding name in the A column IF that name is in the first column of my named range List. It works fine.
However, I would like to filter that to only include names from List that have the boolean value equal to 1 (ie. Index(List;;2) = 1.
How is this possible?
This is what I tried but it gives me a #REF! error:
=SUMPRODUCT(SUMIF(A:A;Index(List;;1)*Index(List;;2);B:B))
Probably best to switch to an array formula**:
=SUM(SUMIF(A:A,IF(INDEX(List,,2),INDEX(List,,1)),B:B))
**Array formulas are not entered in the same way as 'standard' formulas. Instead of pressing just ENTER, you first hold down CTRL and SHIFT, and only then press ENTER. If you've done it correctly, you'll notice Excel puts curly brackets {} around the formula (though do not attempt to manually insert these yourself).
Since your Named Range consists of discontinous ranges, when INDEXing it you will need to include INDEX's 4th parameter (area_num) in order to clarify which of the ranges ($B$2:$B$100 or $L$2:$W$100) you wish to refer to, e.g.:
=INDEX(List,60,1,**2**)
which will return the value in cell L61.
Regards
I know how to make a named range in Excel.
I have a spreadsheet, with various columns going across as parameters, and then finally a formula in the last cell. This is repeated many times in each row, with each row having a different set of data, and the formula updated to reference the correct row index.
However, the formula looks like (three rows worth):
=G2*(10*D2 + 20*E2 + 5*F2)
=G3*(10*D3 + 20*E3 + 5*F3)
=G4*(10*D4 + 20*E4 + 5*F4)
I would like to use named ranges, but I can't find a way to do something like
=Count * (10*var1 + 20*var2 + 5*var3)
where count, var1, var2, and var3 automatically update to be the particular column of the current row. I can create a named range for every cell, but that isn't helpful. I can name range the column, but then I can't find a way to put an offset into the formula.
Also the whole point of this is readability, so if it ends up being some nasty complex formula function call, that probably doesn't help too much.
Simple, at least when using Excel 2010:
name your column: select full column, enter name
use column name in formula; Excel will combine the referenced column with the current row to access a single cell.
Using the example from Alex P:
select column D by clicking the column header containing the "D", enter name "input1" into name field, and press Enter.
repeat for columns E to F, using "input2" and "input3", respectively.
Do not define additional names defining names "input1" [...] as in example above!
use the formula as given in the example above
Attention:
Using named columns this way, you cannot access any other row as the one your formula is in!
At least I'm not aware of the possibility to express something like <ColName>(row+1)...
I would suggest creating a Table. Select your range A1:H4, then go to the Tables widget > New > Insert Table with Headers (on Mac). This will mark A2:H4 as body of the table, and A1:H4 as header.
From that, you get:
Whatever you put into the header column will define the name for this column automatically, e.g. Count, Radius, Density, Height
You can then write your formula using =[#Count]*(10*[#Radius] + 20*[#Density] + 5*[#Height])
When you change the formula in cell H2, Excel will automatically "copy down" this formula to all cells in column H. So no more accidental inconsistencies in the formulas.
When you need to add another row, simply click the last cell (in our example H4) and hit Tab. Excel adds another row, and also makes sure to "copy down" your formula into the new row.
If you need a total row, add it with the Total Row checkbox in the Tables widget. Excel adds a total row automatically. If you click any cell in the total row, you can change the "total formula" with the "▼▲" button, for example to calculate the Average instead of the Sum of the column.
If you have a long table and scroll down so that the header is not visible anymore, Excel automatically displays the column header instead of the column names (Count instead of G for example).
I can really recommend the video You Suck at Excel with Joel Spolsky which explains all of that.
Suppose I have the following numbers set up in columns D to F in rows 2 to 4:
D E F G
2 10 15 20
3 1 2 3
4 20 30 40
Now suppose I want the value in column D to be known as input1, column E to be input2, and column F to input3:
In Insert > Name > Define...
input1 RefersTo =OFFSET(Sheet1!$D$2,0,0,COUNT(Sheet1!$D:$D),1)
input2 RefersTo =OFFSET(Sheet1!$E$2,0,0,COUNT(Sheet1!$E:$E),1)
input3 RefersTo =OFFSET(Sheet1!$F$2,0,0,COUNT(Sheet1!$F:$F),1)
Now if I write my formula in column G as follows I should get correct answers:
G2 =(10*input1+20*input2+30*input3) // 1000
G3 =(10*input1+20*input2+30*input3) // 140
G5 =(10*input1+20*input2+30*input3) // 2000
I haven't fully reviewed the previous answers, but I think this is closer to what #Jason Coyne the OP was looking for. So, I hope I get a lot of up votes. ;-)
Excel allows your formula to refer to tables and columns by name if you "Format as Table". Here is an article titled Using structured references with Excel tables that goes into detail.
FWIW, it looks like this feature has been available since Excel 2007.
Here is a screenshot of an example:
You should be able to see the formula in E2 is =[#Count] * (10*[#Var1] + 20*[#Var2] + 5*[#Var3]) which is pretty close to what #jason-coyne wanted to type.
I don't like that you are forced to pick a style (or define a new one if you don't see a style you like). The good news is you can reformat the cells all you wish without undoing the "tableness".
It insists on turning on auto-filter. But, auto filter is easy to turn off (see the Filter Button checkbox under the Table Tools Design menu).
It also insists on having non-empty, unique values in the header row (Which kinda makes sense). If you delete a header cell, or insert a column, Excel will invent a new, unique name and stuff it in for you. D'oh!
If you want a column to not have a header, you can enter an apostrophe (') followed by one or more blanks. Remember header values need to be unique, so keep adding blanks if you want more than one column without a header.
If you would like to download the sample workbook in the screenshot, here is a link: https://filebin.ca/3vfaSDn4NLEA/SampleWorkbook.xlsx
Adding to Alex P's answer:
Instead of using =OFFSET(Sheet1!$D$2,0,0,COUNT(Sheet1!$D:$D),1) as the formula for input1, I recommend to use =Sheet1!$D$2:INDEX(Sheet1!$D:$D,COUNT(Sheet1"$D:$D))
It produces the same result, but it is non-volatile, i.e., only recalculate when a predecessor cell changes. This is much better in a larger model!
If you're using VBA, then you can select the whole column and name it, say MyCol, in the name box (upper left input box). The in your code you can refer to a cell in the column MyCol (line 12) using the following code:
Cells(12, Range("MyCol").Column)
You might be able to use the row() function. This returns the current row that you are in. So depending on the layout of the spreadsheet you can use it like this:
=offset(NamedColumn1, row()-1)
The -1 is because you are saying how many rows to move down from row 1 which if you are in row 1 you want to be 0.
Use the Excel feature called named references.
To name a cell or range of cells
select that cell or range of cells
Enter its name in the Name Box ( its left of the formula widget and has the cell name )
You can't use names that conflict with cell names, like k0.
The named cells can be used if formulas. E.g.,
=pi*radius*radius
I'd like to propose a slight variation of the cell reference made by Dror. This will work as well:
Range("MyCol").Rows(12)