Recursive Function & Looping In Excel - excel

I am looking for some guidance in looping through a function in Excel within a table without running into a circular reference error. I've spent quite some time trying out COUNTIF, MATCH, Essentially, I need to create a function/formula for the "Desired Date" column so that it takes value from the "Original Date" column and changes the value based on the following parameter:
If a date in the Original Date column does not exist within the previous values of the Desired Date column, it will list the exact date. I've already solved this part with IF and COUNTIF functions.
If a date in the Original Date column already exits within the previous values of the "Desired Date" column, it will add +1 day(s) until all the values within the Desired Date column have unique dates.
Here's what I would like the function to do:
Row 1 contains the original date value as 8/1, since no other values exist in the desired row column, it will return 8/1.
Row 2 contains the original date value as 8/1, but since row 1 of the desired date value already contains value 8/1, it will add +1 day so it becomes 8/2.
Row 3 contains the original date value as 8/1, but since row 1 & row 2 of the desired date contain the value, it will add +2 days, so it becomes 8/3.
Row 6 contains the original date value as 8/3, but since row 3 of the desired date contain the value, it will add +1 day so it becomes 8/4.
If at any given point a date within the original date changes, the values in desired dates should change accordingly by adding a variable amount of days until all values within the Desired Dates column are unique.
Row
Original Dates
Desired Dates
1
8/1/2021
8/1/2021
2
8/1/2021
8/2/2021
3
8/1/2021
8/3/2021
4
8/12/2021
8/12/2021
5
8/12/2021
8/13/2021
6
8/3/2021
8/4/2021
7
8/4/2021
8/5/2021
8
8/3/2021
8/6/2021
9
8/13/2021
8/14/2021
I've spent well over 9 hours on this issue so any help at this point would be very much appreciated. I wouldn't mind using VBA but a function would be preferred for compatibility purposes.
Thank You!

One approach might be to generate dates starting with the date in the first column but ignoring any dates that have already been used (countif>0), then pick the lowest of these:
=LET(maxdate,$D$2,
startdate,B2,
seq,SEQUENCE(maxdate-startdate,1,startdate),
MIN(IF(COUNTIF(E$1:E1,seq),maxdate,seq)))
or slightly shorter
=LET(maxdate,$D$2,
startdate,B2,
seq,SEQUENCE(maxdate-startdate,1,startdate),
MIN(IF(COUNTIF(E$1:E1,seq)=0,seq)))
If you don't have Excel 365, you can use Row instead of Sequence:
=MIN(IF(COUNTIF(E$1:E1,ROW(INDEX(A:A,B2):INDEX(A:A,$D$2)))=0,ROW(INDEX(A:A,B2):INDEX(A:A,$D$2))))
entered as an array formula using CtrlShiftEnter
EDIT
If you wanted to concatenate as in your comment, you wouldn't be able to use Min (because the values wouldn't be numeric) but you could use index/match to find the first available date for a particular person:
=LET(maxdate,$D$2,
startdate,A2,
name,B2,
seq,SEQUENCE(maxdate-startdate,1,startdate),
seqName,seq&name,
INDEX(seqName,MATCH(0,COUNTIF(H$1:H1,seqName),0)))
If you wanted to make the dates appear as a date rather than a number, you could wrap them in Text:
=LET(maxdate,$D$2,
startdate,A2,
name,B2,
seq,SEQUENCE(maxdate-startdate,1,startdate),
seqName,TEXT(seq,"mm/dd/yy")&name,
INDEX(seqName,MATCH(0,COUNTIF(H$1:H1,seqName),0)))

Related

How to filter out partial match in an Excel row?

I have an Excel sheet with dates in the rows. A given month should be used only once in a row. How can I filter out, if there are two dates in the same row from the same month?
For example I have the following array, and I would like to have as a result, that there is a match in this row (2012-03).
2012-03-04 2012-02-05 2012-04-06 2012-03-07 2012-10-08 2012-11-09 2012-12-10
I have tried to combine aggregate and match functions, but I cannot find out how to do it properly.
One of my codes, of course it gave an error:
=aggregate(9,6,(MATCH("*"&LEFT(A8,7)&"*","*"&LEFT(b8,7)&"*",0), MATCH("*"&LEFT(b8,7)&"*","*"&LEFT(c8,7)&"*",0)))
Ok, now I have tried another way, and I could get a solution, but with a code which is like a km long...I have first created a new dataset, cutting down the days by using: =""&LEFT(A8,7)&""
Then I have compared all the cells in a given row of my new dataset. Could someone help me how to shorten the exact( ) parts? The aim is to compare all.
=if((or(exact(A2, B2), exact(A2,C2),exact(A2,D2),exact(A2,E2),exact(A2,F2),exact(A2,G2),exact(A2,H2),exact(A2,I2),exact(A2,J2),exact(A2,K2),exact(A2,L2),exact(A2,M2),exact(A2,N2),exact(A2,O2),exact(A2,P2),exact(A2,Q2),exact(A2,R2),exact(B2,C2),exact(B2,D2),exact(B2,E2),exact(B2,F2),exact(B2,G2),exact(B2,H2),exact(B2,I2),exact(B2,J2),exact(B2,K2),exact(B2,L2),exact(B2,M2),exact(B2,N2),exact(B2,O2),exact(B2,P2),exact(B2,Q2),exact(B2,R2),exact(C2,D2),exact(C2,E2),exact(C2,F2),exact(C2,G2),exact(C2,H2),exact(C2,I2),exact(C2,J2),exact(C2,K2),exact(C2,K2),exact(C2,L2),exact(C2,M2),exact(C2,N2),exact(C2,O2),exact(C2,P2),exact(C2,Q2),exact(C2,R2),exact(D2,E2),exact(D2,F2),exact(D2,G2),exact(D2,H2),exact(D2,I2),exact(D2,J2),exact(D2,K2),exact(D2,L2),exact(D2,M2),exact(D2,N2),exact(D2,O2),exact(D2,P2),exact(D2,Q2),exact(D2,R2),exact(E2,F2),exact(E2,G2),exact(E2,H2),exact(E2,I2),exact(E2,J2),exact(E2,K2),exact(E2,L2),exact(E2,M2),exact(E2,N2),exact(E2,O2),exact(E2,P2),exact(E2,Q2),exact(E2,R2),exact(F2,G2),exact(F2,H2),exact(F2,I2),exact(F2,J2),exact(F2,K2),exact(F2,L2),exact(F2,M2),exact(F2,N2),exact(F2,O2),exact(F2,P2),exact(F2,Q2),exact(F2,R2),exact(G2,H2),exact(G2,I2),exact(G2,J2),exact(G2,K2),exact(G2,L2),exact(G2,M2),exact(G2,N2),exact(G2,O2),exact(G2,P2),exact(G2,Q2),exact(G2,R2),exact(H2,I2),exact(H2,J2),exact(H2,K2),exact(H2,L2),exact(H2,M2),exact(H2,N2),exact(H2,O2),exact(H2,P2),exact(H2,Q2),exact(H2,R2),exact(I2,J2),exact(I2,K2),exact(I2,L2),exact(I2,M2),exact(I2,N2),exact(I2,O2),exact(I2,P2),exact(I2,Q2),exact(I2,R2),exact(J2,K2),exact(J2,L2),exact(J2,M2),exact(J2,N2),exact(J2,O2),exact(J2,P2),exact(J2,Q2),exact(J2,R2),exact(K2,L2),exact(K2,M2),exact(K2,N2),exact(K2,O2),exact(K2,P2),exact(K2,Q2),exact(K2,R2),exact(L2,M2),exact(L2,N2),exact(L2,O2),exact(L2,P2),exact(L2,Q2),exact(L2,R2),exact(M2,N2),exact(M2,O2),exact(M2,P2),exact(M2,Q2),exact(M2,R2),exact(N2,O2),exact(N2,P2),exact(N2,Q2),exact(N2,R2),exact(O2,P2),exact(O2,Q2),exact(O2,R2),exact(P2,Q2),exact(P2,R2),exact(Q2,R2))),"same month","ok")
Thank you in advance.
I am not sure if there is a better way, but this is how I'd tackle the problem based on my Excel knowledge:
Add data of dates above in cells A1-G1
On row below date add formulas for dates: A2=DATE(A1) ..... G2=DATE(G1)
At the end of the original row of dates add the numbers 1 thru 12:
using formula cell H1=1, I1=H1+1 ..... S1=R1+1
After the months on row 2:H2=COUNTIF($A2:$G2,H1) ..... S2=COUNTIF($A2:$G2,S1)Counting frequency for each of the 12 months
T2=MAX(H2:S2)
Then select on cell T2being more than 1.
Here it is as a Google sheet (you can download it and open in Excel if you want)
Maybe this will help. Assume that the range of dates is in $A$1:$G$1. Also assume that the entries are numerical dates; if they are instead text you can handle this by using the DATEVALUE function. Then we can get the years and months of the range with:
{=YEAR($A$1:$G$1)}
{=MONTH($A$1:$G$1))
This and all other formulas must be entered as array formulas (CrtlShiftEnter).
We next convert back to a date, but use 1 for the day, so that all dates get shifted to the first day of the month (this means that any dates from the same month are shifted to the same date):
{=DATE(YEARS,MONTHS,1)}
We can produce an NxN comparison of the shifted dates by:
{=TRANSPOSE(SHIFTED_DATES)=SHIFTED_DATES}
We can count the number of True's in this array by:
{=SUM(--(ARRAY))}
If there we no dates from the same month we'd expect this to sum to N because this method compare each date to itself as well as the other dates. The causes the N elements on the main diagonal of this array to be True. If any dates are in the same month off-diagonal elements will also be True. So to detect if there are dates from the same month we make the comparison:
{=SUM(--(ARRAY)) > N}
or more generally:
{=SUM(--(ARRAY)) > COUNT($A$1:$G$1)}
Rolling all of these up into one formula:
=IF(SUM(--(TRANSPOSE(DATE(YEAR($A$1:$G$1),MONTH($A$1:$G$1),1))=DATE(YEAR($A$1:$G$1),MONTH($A$1:$G$1),1)))>COUNT(DATE(YEAR($A$1:$G$1),MONTH($A$1:$G$1),1)),"same month","ok")
If your dates are in a range other than $A$1:$G$1 then make the appropriate substitutions.
Hope that helps.

Finding the last occupied cell using a formulae

This formulae "works", but it seems a bit long winded. Can anyone suggest an "easier" formulae. It returns the value in the 5th Column to a date in the 1st column which is called from a separate (and discrete) worksheet. If there is no data in the 5th column (because we haven't reached or passed that date), then the latest available data is called ($A$20, is the "calling date, on a current worksheet):-
IF(VLOOKUP($A$20,'[FTSE100.xlsx]Meteor Step Down
Plans'!$A$18:$E$2828,5)="",VLOOKUP(HLOOKUP(A20,'[FTSE100.xlsx]Meteor Step
Down Plans'!$A$18:$A$2628,MATCH(TRUE,INDEX(ISBLANK('[FTSE100.xlsx]Meteor
Step Down Plans'!$E$18:$E$2828),0,0),0)-1),'[FTSE100.xlsx]Meteor Step Down
Plans'!$A$18:$E$2828,5),VLOOKUP($A$20,'[FTSE100.xlsx]Meteor Step Down
Plans'!$A$18:$E$2828,5))
The formula is in a different workbook to the data. The formula is used to determine the last value in an array, the first column of which is a date range (01/01/2000 to 31/12/2027....say) The required data is in column 5. Entries may be up to date (i.e. the last entry was made today, therefore it will pickup todays value. The last entry may have been several days (weeks) ago, therefore it will pick up the last value in the designated column (column 5). I don't see why it can't go into a named range, as the array size is fixed. Does that help?
Thanks Ron, nearly there. That works beautifully for "missing" dates in the array. i.e. when Saturday and Sunday dates are missing, it finds the value (in column 5) of the previous Friday. However (and there is usually a "however"), if $A$20 is a date in advance of the date of the last data in the array i.e. column 5 is blank at that date, your formulae returns 0 (zero), instead of the data as at the last date that data has been entered. i.e. enter 02/04/2018 and your formulae returns 0, not the data at the last date available 28/02/2018. Is that a little more clear?? (Thank you anyway, for spending the time - I'm still trying to work out how your formulae works as it does. Is the "/" significant (other than being a "divide by" symbol, if so it's something I've never come across before? Regards...........Mike. P.S. The dates in the array (Column 1) are all in from 2016 to 2027 (excluding weekend and bank holidays), and are arranged in ascending order i.e. from 01/01/2016 to 31/12/2027
Ron - Sorry mate, buy I can't see a "second" formulae???
If I understand what you want to do correctly, (and that is hard to do since you give NO examples of your data, actual output or desired output), try:
=LOOKUP(2,1/((myDate>=A:A)*(LEN(A:A)>0)),E:E)
If it is the case that you have dates in column A and no entries in Column E, then you might have to do something like:
=LOOKUP(2,1/((myDate>=A:A)*(LEN(A:A)>0)*(LEN(E:E)>0)),E:E)
Of course, you will have to modify the cell references and named range to refer to the proper workbooks and cell.
Possibly something like:
=LOOKUP(2,1/(($A$20>='[FTSE100.xlsx]Meteor Step Down Plans'!$A$18:$E$2828)*(LEN('[FTSE100.xlsx]Meteor Step Down Plans'!$A$18:$E$2828)>0)),'[FTSE100.xlsx]Meteor Step Down Plans'!$E$18:$E$2828)
This should return the item from Column E that is either at or above the same row as myDate in Column A. If myDate does not exist in column A, it will match the nearest earlier date in Column A and return from that row in Column E.
In the second version of the formula, it also checks that there is an entry in Column E matching the column A date, and, if not, it will look above.

Excel Return Date before another date by another column name

I have two sheets of data with the following.
I want return the date from sheet 2 on sheet 1 with the start date BEFORE the remove date. For example. For Customer A, the remove date is 12/29/2016. I would want to return the date of 12/20/2014 from sheet 2 as it is the next previous date from the remove date of 12/29/2016 from sheet 1 and is removed prior to the third date of 1/20/2017. Similarly for Customer B, the date returned would be 11/9/2013.
Vlookup will not work as there are more than one unique value for customer and I had no luck with index and match. Is there any other possible solution?
Here is an edit. The Sumproduct and aggregate method for the start date works great. The issue is I need the last date to be the first record after the replacement date. So in this case, it would be 2/1/16. Using the Min or Max sumproduct and aggregate method, I get either 0 or the max date of 3/22/17, which is not what I want.
Since dates are (for all intents and purposes) numbers, this is really nothing more than a pseudo-MAXIFS question. Try,
=aggregate(14, 6, (b2:b7)/((a2:a7="A")*(b2:B7<date(2016, 12, 29))), 1)
For those that don't have the latest version of excel and can't use maxifs, we can do an array formula: take the max date that is less than the date corresponding to A
=SUMPRODUCT(MAX((A9:A14=A3)*(IF((B9:B14)<B3,B9:B14))))
entered as array formulae (Ctrl+Shift+Enter)

EXCEL - SUM column if date matches TODAY()

I've tried using SUMIF to obtain my results but it doesn't work properly.
I have a row of dates (XX/XX/XXXX format) and I would like to check this row for the current date.
If the row contains the current date, then I would like to sum the total of that column and row 5-20.
For example - today is 10/13/2016. I would like to search for TODAY() in a certain row (Row 1 for example), and if TODAY() is found, then total this column from row 1 down to row 3.
--A-- --B--
10/13/2016 10/14/16
1 50 10
2 10 4
3 5 6
The result should be 65 only IF the date matches TODAY().
I've also checked on giving the column letter based on the date but with no luck.
Any tips are appeciated! Thank you.
I think you can achieve this with a simple IF and a SUM
i.e. in your example above if you want the result to appear on the bottom row you can just use:
=if(B2=today(), sum(B3:B5), "")
This will display the sum at the bottom of the column for columns where the date = today and a blank in the other columns
You need to use the OFFSET function. You can find the documentation here: https://support.office.com/en-us/article/OFFSET-function-C8DE19AE-DD79-4B9B-A14E-B4D906D11B66
In your particular example the following formula will work:
=SUM(OFFSET(D2, 1, MATCH(B2, $D$2:$F$2, FALSE) - 1, 20))
You can see the formula working below. Assuming you know what the SUM formula is doing, I will explain what the OFFSET formula is doing:
First Parameter: Says start at cell D2
Second Parameter: This is how many row up/down do you want to do. In your case you need start at row below the date so '1' it is.
Third Parameter: This is how many columns to the right do you want to
go. Well the number of columns you want to go is based upon where
your date is. So this uses the match formula to figure out how far
to the right to go.
Fourth Parameter: This is how many row do you want to include. I just picked 20 to include the 20 rows below the selected cell.
You obviously need to modify the parameters a little bit to fit your exact data shape.
So I'll give it a shot:
{=SUM(HLOOKUP(TODAY(),Table_With_Dates_and_Three_Rows_Cell_Reference,{2,3,4}))}
NB: Don't type {} but put the formula inside it and then hit Ctrl+Shift+Enter to create what is called an array formula (it does array calculations element by element then submits the aggregating function value---in this case that is sum).

Finding the value in excel or vba

Column A Column B
13-06-2013 10:50
13-06-2013 11:30
13-06-2013 12:40
14-06-2013 10:30
I need to find the values which are before a particular entry date and time.
For example, say I want to find the values in the example table above that are immediately prior to the values "13-06-2013" and "12:30".
Since 12:30 is not in column B, how do I find the values I am looking for? The answer should be 13-06-2013 and 11:30.
C7 =VLOOKUP(A7&B7,A1:C4,3,TRUE)
Here A1 = B1&C1
A B C
1 414380.451388888888889 13-06-2013 10:50
2 414380.479166666666667 13-06-2013 11:30
3 414380.527777777777778 13-06-2013 12:40
4 414390.4375 14-06-2013 10:30
5
6 Enter date Enter Time Returned Time
7 13-06-2013 12:30 11:30:00
Setting 'range_lookup' as 'True' adds the flexibility to return the closest approximate value if the exact value is not available.
I think you're looking for something like this. using index and match.
I didn't take into account the date for now. but this gives you an example.
You can compare date strings with operators like > or < etc. Concatenate your values in columns A & B, compare to the desired date/time string. In cell C1 put the following formula, and then drag down:
="13-06-2013 12:30"<A1&" "&B1
or more specifically, depending on which "12:30" you want (AM or PM), ="13-06-2013 12:30AM" or ="13-06-2013 12:30PM"
Your data in column B may default to AM unless otherwise specified/imported differently, so you may need to tweak the data or to account for this.
Here is another approach to answering your question that uses a combination of MATCH, INDEX, and array operations to provide a compact formula solution that does not rely on helper columns.
I'll assume that your two columns of dates and times are in cells A2:B5, and the two date and time values that you want to look up are in cells A9:A10. Then the following two formulas will return what you require, the latest date and time values in your data that are less than or equal to the date and time that you are looking up. (The dollar signs in the formulas are hard on the eyes, but they are important if you will need to copy the formulas to other locations; for clarity, I omit them in the discussion that follows.)
DATE: =INDEX($A$2:$B$5,MATCH(A9+A10,$A$2:$A$5+$B$2:$B$5,1),1) --> 13-06-2013
TIME: =INDEX($A$2:$B$5,MATCH(A9+A10,$A$2:$A$5+$B$2:$B$5,1),2) --> 11:30 AM
These are array formulas and need to be entered with the Control-Shift-Enter key combination. (Of course, only the bits starting with the equal (=) sign and ending with the last parenthesis need to be entered into the worksheet.)
Things to consider:
The formulas assume that your data are valid Excel date and time values. Excel date values are whole numbers that count the number of days that have elapsed since January 1, 1900; Excel time values are decimal amounts between 0 and 1 that represent the fraction of 24 hours that a particular time represents. While your example data don't display AM or PM, I assume that their underlying values do have that information.
If your values are text (having been imported from another source, for instance), you should convert them to date/time values, if lucky, using only Excel's DATEVALUE and TIMEVALUE functions; if not so lucky, using some combination of Excel's string manipulation functions as well. (The values could be kept as strings, but you would almost certainly need to massage them so they would compare correctly "alphabetically" - much easier just to deal with Excel date/time values.)
If they are not already, your dates and times will need to be sorted from smallest to largest. (Your sample looks like they are sorted, and the formulas assume as much.)
How the formulas work
The basic idea behind the formulas is two-fold: first find the row in your data that holds the latest (largest) date and time that is still less than or equal to the date and time you are looking up. That row information can then be used to fetch the final result from each column of the data range (one for date and one for time).
Since both date and time figure in to what point in time is latest, the date and time components of both the value to be looked up and the values that will be searched must be combined somehow.
This can be achieved by simply adding the dates and times together. This does nothing more than what Excel does: an Excel date/time value has an integer part (the number of days since 1/1/1900) and a decimal part (the fraction of 24 hours that a particular time represents).
What is neat here is that the adding up of the dates and times - and the lookup of the particular date and time - can be done all at once, on the fly.
Take a look at the MATCH: The cells that contain the date and time to be looked up - A9 and A10 - are added together, and then this sum is matched against the sum of the date column (A2:A5) and the time column (B2:B5) - an operation that is possible of Excel's array arithmetic capabilities. The match returns a value of 2, indicating correctly that the date and time that fill your requirements are in row 2 of the data table.
DATE/TIME MATCH: = MATCH( A9+A10, A2:A5 + B2:B5, 1 ) --> 2
The 1 that is the final argument to the MATCH function is an instruction that the match results be calculated to be less than or equal to the value to be looked. It is the default value and is often omitted, or replaced with another value (for example, using a value of 0 will produce an exact match, if there is one).
(For readability, I've removed the dollar signs that are in the full formula; these anchor a range so that it remains the same even if the formula is copied to another location.)
Having figured out the row to look in, the rest of the formula is straightforward. The INDEX function returns the value in a data range that is at the intersection of a specified row and column. So, for the date in question, the formula reduces to:
DATE FETCH: = INDEX( A2:B5, 2, 1) --> 13-06-2013
In other words, INDEX is to return the value in the second row and first column of the data range A2:B5.
The formula for the time proceeds in exactly the same fashion, with the only difference that the value is returned from the second column of the data range.

Resources