Need solutions for the queries posted in the below link,
http://www.mrexcel.com/forum/excel-questions/334740-dynamically-sum-row-values-based-column-headers.html
Having PersonWeek as separate column with sum of weeks should be displayed.
Quest: Dynamically sum row values based on column headers?
It is good form to re-post the question in its entirety on this site; nevertheless:
What you are looking for is relatively straight forward. There are a lot of ways to accomplish this but I suggest that you use combination of the 'Match' function and the the 'Offset' function. The Offset function creates a range based on a given start point, moving up/down / left/right as indicated, with a given height / width. For example:
=Offset(B2,1,2,3,4)
Indicates the range D3:G5. This is the range given by starting at cell B2, moving 1 row down and 2 columns to the right, and going for a total of 3 rows and 4 columns.
So the remaining point is to determine where to start and stop your offset.
First, the first field in your Offset function will be cell A1, as that is the top-left corner of your data table. To find how many rows to move down, you need to find what project you are referring to (I will assume that cell A6 is where you enter the project name that you care about, A7 is where you enter the first week you care about, and A8 is where you enter the last week you care about). To find how many rows to move down from A1, then, use Match:
=Match(A6, A2:A5,0)
To find how many columns to move to the right to find your first week, use Match again:
=Match(A7, B1:G1,0)
Assuming you only want to look at a single project, we know how high we want the range to be (1).
To find how wide we want the range to be, we need to know your ending week, less your starting week:
=(Match(A8,B1:G1,0)-Match(A7, B1:G1,0))
So the whole thing together will be:
=Offset(A1,Match(A6, A2:A5,0),Match(A7, B1:G1,0),1,Match(A8,B1:G1,0)-Match(A7, B1:G1,0))
Now the only thing left is to wrap the newly defined range in a 'sum' function, like so:
=Sum(Offset(A1,Match(A6, A2:A5,0),Match(A7, B1:G1,0),1,Match(A8,B1:G1,0)-Match(A7, B1:G1,0)))
This formula will create an error if someone enters a project name / weekname in a way that isn't found in your table - so in cells A6-A8 you may want to use data validation to only allow those names to be entered - let me know if you would like elaboration on that.
Related
I have a table where I enter the qualification times manually Name and Timer. It calulates the Final Time automatically, but I want it to sort the Final Time and Name in the right side from the fastest to the slowest, as in the second image. I tried using VLOOKUP and INDEX, but didn't manage to get it. I need help finding the right formulas to Cells I$ and J$. I hope to get a answer from here.
Hope to get it like following:
Use this formula in your column J. Enter it in J3 and copy down. As you see, it refers to column H where it expects the numbers 1 and up. So, it will look for the smallest, second smallest etc values in the given range.
=SMALL($D$3:$D$6,H3)
In I3 please enter the formula below and copy down.
=INDEX($B$3:$B$6,MATCH(J3,$D$3:$D$6,0))
It looks for the value the SMALL function extracted and finds the matching name.
So I'm not a fan of VBA and I recently learned that OFFSET can be used with COUNTA to flashfill a range as far at it is as long as you aim for a longer range than you have data. Now I want to be able to achieve this both for columns and rows at the same time, where the rows are averaged. Could this be done? I am banging my head against the wall to find some logic to do it, but can only manage to combine it in a way that multiplies the rows with the number of the column.. which is not desired, of course.
I have posted a Minimal Reproducible Example in Excel Online:
https://onedrive.live.com/view.aspx?resid=63EC0594BD919535!1491&ithint=file%2cxlsx&authkey=!ALmV0VtFb7QZCvI
If you see Cell J9 and J11 you will see what I want to combine. The three rows in J11 and down, I want to average in J10, and spill/flashfill (like J9 and 11 does automatically because of the formula already) them from to the right, for as many columns as there data in the range A1-G4..
So I have raw data of numbers with titles in A1-G4, and by writing =OFFSET($A$1:$A$1,0,0,1,COUNTA($A$1:$EV$1)-1) in J9 I get all the titles of the columns filled from left to right, and by writing =OFFSET($A$1,1,0,COUNTA($A:$A)-1) in J11 I get the rows of the first column filled from top to bottom. They can also be combined, by writing OFFSET(Days,1,0,COUNTA($A:$A)-1,COUNTA(Days)), where "Days" is =OFFSET($A$1:$A$1,0,0,1,COUNTA($A$1:$EV$1)-1) (in a named range for readability) or OFFSET($A$1:$A$1,0,0,1,COUNTA($A$1:$EV$1)-1) without using a named range
As a thought, though I'm not sure how to implement it, maybe this could somehow be used in some form to get the column reference for the horizontal part in combination with =AVERAGE(OFFSET($A$1,1,0,COUNTA($A:$A)-1))
=MID(ADDRESS(ROW(),COLUMN()),2,SEARCH("$",ADDRESS(ROW(),COLUMN()),2)-2)
..found at https://superuser.com/questions/1259506/formula-to-return-just-the-column-letter-in-excel/1259507
Now, based on your explanation, here is the screenshot of my test:
Section A1:Exxx
I have converted that section into a Table, called «TblData», having numerous avantages:
It expands automatically without any additional efforts/formula
We can identify Data by its Columns attributed automatically by the Table [#1], [#2],[#3], [#4], [#5]
Section J9:N9
As a replica of the table name, I have used the following formula to retrieve it:
=INDEX(TblData[#Headers],1,COLUMN(A1)) '<--- This is for J9
=INDEX(TblData[#Headers],1,COLUMN(E1)) '<--- This is for N9
Section J11:Nxx
As a replica of the Table Content, I have used the following formula to populate the content:
=INDEX(TblData,ROW($A1),MATCH(J$9,TblData[#Headers],0)) '<--- This is on J11
=INDEX(TblData,ROW($A3),MATCH(N$9,TblData[#Headers],0)) '<--- This is on N13
Section J10:N10
Now this is the interesting part of the Average, so here is the formula I used for it:
=AVERAGE(TblData[1]) '<--- This is on J10
=AVERAGE(TblData[5]) '<--- This is on N10
NB: (1) Instead of using the Content below J10:N10, I prefer to reuse the Table as it expands automatically as more rows are added.
(2) Unless it is really necessary, I feel it is a double work as well to replicate again A1:Exxx from J9:Nxxx, because you can use the Table for whatever you need, with less maintenance.
Kindly find attached the file as well after I updated those items:
File Link: https://drive.google.com/open?id=1wRbpUxg0XLpfGqdvMF4fNKXDrL7xPPWs
We can correspond more below for further info. Hoping you to strech more your compentence :)
Sorry, mate, I can't figure out what you want to calculate. If it makes sense to add J9+J11 then you could just concatenate the two formulas in J9 and J11 with a plus sign. After much deliberation I decided to assume that your question is not one of formula but of formula-writing - "referencing" for short. Therefore I prepared this answer for you, hoping that it will prove helpful.
Building on your named range Days I suggest you create a dynamic named range Data with this formula.
[Data] =OFFSET(Sheet1!$A$1,0,0,COUNTA(Sheet1!$A:$A),COUNTA(Sheet1!$1:$1))
The range thus defined is dynamic in both directions. However, bearing in mind that OFFSET is volatile (slows down your worksheet) you may like to keep its use limited to this one formula and perhaps start the range at A2, but I shall tempt you to break the rule. Now you can use the INDEX function to refer to the Data range.
= INDEX(Data, [Row number], [Column number])
defines a single cell. But by setting either column or row to zero you can define an entire column or row. =INDEX(Data,0,1) defines column 1 of the Data range, =INDEX(Data,1,0) defines its first row.
=INDEX(OFFSET(Data,1,0),0,1) defines the first column of a range moved down by one row from its original position. I recommend the alternative and start the Data range from A2 and perhaps declare another range for the first row if needed.
=AVERAGE(INDEX(Data,0,1)) would draw the same average you already have in your sheet, provided that Data was defined starting at A2. For fun's sake, =AVERAGE(INDEX(OFFSET(Data,1,0),0,1)) would do the same without the change in the range's definition.
=COLUMN() returns the number of the column this formula resides in. So, you could enter =COLUMN()-6 in column G, copy to the right and get a count starting from 1. (You can do the same vertically with the ROW() function.) Applied to your formula, =AVERAGE(INDEX(Data,0,COLUMN()-6)) would return the average from column 1 if entered in column G, and from columns 2, 3 4, etc as copied to the right.
As I said, I don't understand enough of your request to bring this idea to a conclusion but I think that using the method described above will provide you with a tool to copy formulas into the table your sample has at its right. If you would elaborate on your requirement I might be able to assist more.
I have a huge excel sheet that i need to extract some data from...
To simplify what exactly i want to do i'll provide a simple example...
Now allow me to explain what is this and what i am looking to achieve...
In the image the first table to the left contains the following:
B1/B2/B3 which stands for Building 1, 2 and 3
Each building contains 3 floors, F1/F2/F3
Each floor have 3 different tasks that are in progress, T1/T2/T3
In front of each task there are two values V1/V2 which are planned progress and actual progress for the task respectively.
On the right table i want to extract all the values for Task 1 (T1) from the left table for all Buildings and all Floors...
The first thought would be to do a manual extraction by linking each cell on right table with its corespondent on left table, but, with hundreds of buildings and 20th or 30th of floors and 10th of tasks this manual extraction seems like a month work...
The other way is to do that automatically by finding each task and extracting its data to the new table, however there is a huge problem here...
Each similar task is named the same so there are nine T1 and nine T2 and nine T3 in our example. And same goes for the floors there are three of each...
The only thing that is unique are the Buildings B1/B2/B3
So my question is, (explaining what i had in mind):
Is there a way to run a search for lets say in our example B2 (which is Building 2) and once it is found it starts another search from this position (A14) and down looking for 'the first only occurrence' of F2 (which is Floor 2) (so it does not find F2 for Building 3 as well) and once it is found it starts a new search from This B2/F2 position (A19) and down looking for 'the first only occurrence' of T1 (which is Task 1) and then when it is found it extract the numbers in front of it (lets say the one under the second value V2) and place it in the right table which is the Task 1 table (T1) under V2 for B2 in front of F2.
How to achieve that?, what would be the formula or whatever that should be in M5 in our example to get this job done? if it is even possible by a way or another!
Thanks for your help in advance,
Best Regards.
The formula for M5 would be (entered as an array formula using ctrl+shift+enter):
=INDEX($B:$C,MATCH($I$1,IF(ROW($A:$A)>MATCH($I5,IF(ROW($A:$A)>MATCH(IF(M$2="",L$2,M$2),$A:$A,0),$A:$A),0),$A:$A),0),MATCH(M$3,$B$1:$C$1,0))
This can be copied to fill in the rest of the table.
EDIT You can make it faster by limiting it to specific ranges instead of whole columns:
=INDEX($B$1:$C$39,MATCH($I$1,IF(ROW($A$1:$A$39)>MATCH($I5,IF(ROW($A$1:$A$39)>MATCH(IF(M$2="",L$2,M$2),$A$1:$A$39,0),$A$1:$A$39),0),$A$1:$A$39),0),MATCH(M$3,$B$1:$C$1,0))
EDIT2: A quick explanation on the nested MATCH formulas: Start with the third MATCH, MATCH(IF(M$2="",L$2,M$2),$A:$A,0). This finds the row in column A that contains "B2" (14), so the formula becomes.
=INDEX($B:$C,MATCH($I$1,IF(ROW($A:$A)>MATCH($I5,IF(ROW($A:$A)>14,$A:$A),0),$A:$A),0),MATCH(M$3,$B$1:$C$1,0))
The "14" is used in the comparison for the second IF, which will return all the values in column A as an array except the first 14 rows, which will be FALSE in the array. The second MATCH can then find the first instance of "F2" in that array (19). The formula is now:
=INDEX($B:$C,MATCH($I$1,IF(ROW($A:$A)>19,$A:$A),0),MATCH(M$3,$B$1:$C$1,0))
Repeat the same process as before to get the row of the first instance of "T1" after row 19. This is the row fed to INDEX. The last MATCH gives the column for INDEX.
I just want to say up front that I have very little skill in Excel.
Actually, I never use it.
What I have been trying to do is create a function that gets the value of a cell of a particular column and the current row.
For example, I want the value of cell:
Column: B
Row: ROW()
What I will ultimately use this to do is average cells in a row.
If there's a better way to do that, feel free to give suggestions, although it would still be neat to learn how to do this if it's possible. =)
I apologize if I messed up in presenting or posting my question; aside from Excel, I'm also new to stackoverflow.
To get the content of cell (B,ROW()) do:
= INDIRECT(CONCATENATE("B", ROW()))
If you just want to calculate the average of a given line of numbers (e.g. first 10 cells in row 2):
= AVERAGE(A2:J2)
The ':' represents an area from the upper left corner (A2) to the lower right (J2).
As mentioned by #MattClarke, you can use =AVERAGE(ROW_NUMBER:ROW_NUMBER) to calculate the average of a whole row (in this case row ROW_NUMBER) where you don't know the exact number of data fields. Pay attention not to use this formula in that exact row (row ROW_NUMBER) to avoid a circular reference. (Thanks #MattClarke for the hint!)
Getting the average across a fixed range of cells is pretty easy: just use a formula like =average(A4:H4) where the parameter specifies the first and last cell. If you want the average of a whole row and you don't know how many columns of data there are, then you can use something like =average(8:8), where the number 8 is the row number of the data to be averaged.
I get the feeling this is close to impossible, but here goes. I have data structured like this:
Test Group 1
pass
fail
pass
fall
Test Group 2
pass
fail
Test Group 3
pass
fail
fail
pass
I want to be able to paste it into Excel and have Excel summarise the percentage of each test group. So it would end up looking like this:
Test Group 1 Percentage Pass: 50%
pass
fail
pass
fall
Test Group 2 Percentage Pass: 50%
pass
fail
Test Group 3 Percentage Pass: 50%
pass
fail
fail
pass
BUT as you can see the test group length is not set, and it may vary. I was hoping is that I might be able to create a formula that follows this logic:
if( A<n> contains "Test")
count A<n> +1 until A<n> contains "Test"
It seems like I'm asking a lot from Excel formulas. I have spent some of today writing a small C# app that will split the configs into separate files so that I could copy and paste separate files into Excel. But it would be great to have fewer steps!
--- UPDATE ----
There were three very interesting approaches to this problem proving nothing is impossible :p
I wanted a solution that allowed me to copy and paste results in and see a load of percentages pop up so I was always sort of looking for a formula solution HOWEVER, please take the time to look at pnuts and Jerrys answers as they reveal some useful features of Excel!
chuffs answer was the one I was looking for and it worked out of the box. For anyone who wants to delve deep into how it works and why, I broke the formula down into steps and filled in some help information. The key to these formulas is combining MATCH, OFFSET and the slightly more obvious SEARCH / FIND / LEFT (I used to use IFERROR(FIND type approach, LEFT seems cleaner :) )
Do look at the documentation for these formulas but to see it all in action with some examples see the Google Spreadsheets I created detailing chuffs answer:
https://docs.google.com/spreadsheet/ccc?key=0AqODI11eAjtldDhDd2dBcFhpZW9SXzEybGtMUWMwM3c#gid=0
---P.S---
For the record I did actually create a C++ program to prettify my data and ouput it as .csv files. If I had had this info I wouldn't have bothered but am glad I tried both routes, it was a fun learning adventure.
A single, array-formula solution to this problem is possible. It requires only that a stop value "Test" be added at the bottom of your column of data.
Assuming your data are in the range A2:A18, here is the formula that would compute the average in cell B2:
=IF(LEFT(A1,4)="Test",
COUNTIF(OFFSET(A1,1,0,MATCH("Test*",$A2:$A$18,0)-1,1),"pass")
/ COUNTA(OFFSET(A1,1,0,MATCH("Test*",$A2:$A$18,0)-1,1)),
"")
The key parts of the formula are expressions that calculate the ranges for the two count functions, COUNTIF and COUNTA.
The COUNTIF function - which counts the number of passes in a group - takes two arguments, the range for the count and the condition to be met by cells counted.
I use the OFFSET function to provide the count range. OFFSETtakes five arguments:
An anchor cell (if a range is provided, the function only uses the top left cell in the range).
The number of rows below (+) or above (-) the anchor cell that the range to be returned will begin.
The number of columns to the right (+) or left (-) of the anchor cell for the start of the return range.
The number of rows to return.
The number of columns to return.
For example, OFFSET(A1,5,2,4,1) will return the range C6:D9.
In the formula, the anchor cell is A1, the row offset is 1 and the column offset is 0, in other words, the start of the range to return is A2.
The number of rows to return is computed by the MATCH function. For the calculation of the average for the first test group, MATCH looks in the range A2:A18 for the row of the first cell that starts with the word 'Test'. A2 is the cell in the pass/fail column just below the cell that starts the test group.
The last cell in the column is A18, which has been added to the data and contains the word 'Test'. This prevents the formula from returning an error for the last test group. Otherwise, the match would return an error because it could not find another occurrence of Test beyond the start of the final group.
Also note that the anchor points for the match range, i.e., $A2:$A$18, leaves unanchored the row reference to the top of the range (the 2 in A2). That's so the range will adjust downward as the formula is copied down so as to find the next, not the previous, occurrence of 'Test'.
Finally, I decrease the number of return rows by 1 to exclude the Text that MATCH found, which belongs to the next group.
The COUNTA functions - which counts the total number of passes and fails in a group - uses the same OFFSET/MATCH expression to get the range for the group.
This is an array formula and so must be entered with the Control-Shift-Enter key combination. Copy the formula down to the bottom of the data (excluding the cell with the 'Test' stop value) to calculate the averages for each group.
For convenience, here is the formula without the breaks shown above. It can be directly pasted into the worksheet (remembering to confirm it with Control-Shift-Enter).
=IF(LEFT(A1,4)="Test",COUNTIF(OFFSET(A1,1,0,MATCH("Test*",$A2:$A$18,0)-1,1),"pass")/COUNTA(OFFSET(A1,1,0,MATCH("Test*",$A2:$A$18,0)-1,1)),"")
Basically Subtotal will meet the requirement, provided some fairly tedious layout adjustments are acceptable.
Preparation:
Assuming Test Group 1 is in A1, insert Row1 and ColumnA, with in A2 =IF(LEFT(B2,1)="T",B2,"") and in C2 =IFERROR(MATCH(B2,{"fail","pass"},0)-1,"") and both formulae copied down as required. (And change fall to fail in source!)
Subtotal:
Select A:C, Data > Outline – Subtotal, At each change in: (1) Test Group 1, Use function: Average, Add subtotal to: check (Column C), uncheck Summary below data, OK.
Tidy up:
1. Move A3:C3 to A1 and A2:C2 to A3.
2. Filter A:C and for ColumnB, Text Filters, Contains add Test, OK.
3. In C3 put ="Percentage Pass: "&C4*100&"%" and copy down to last row numbered in blue (should show #DIV/0!).
4. Highlight A:C for all the rows numbered in blue and embolden.
5. Hide ColumnA and, optionally, hide or delete Rows1:2.
6. Take off filter selection.
Hopefully with preparation as on the left the result would be similar to as shown on the right:
Example re comment to #Jerry's answer:
There are many ways to tackle this -- one possible easy solution is to add a column next to your pass/fail column that says (assuming column A):
=IF(A1="pass",100,0)
if you do that, then the average of those values would be equal to the percentage pass.