Numbering Based on Condition(s) - excel

I'm trying to create auto numbering for Agents that are currently present and has numbers including zeroes 0 in 3rd or 4th column(zero meaning they don't get any stats but they are present)
Agents who has TEXT Value in the 3rd or 4th column are those who are not present (Ex: A = Absent, SL = Sick Leave, VL = Vacation Leave). Meaning, they should not be counted, therefore their value on 1st column should be blank, and therefore this should not stop the auto numbering for the rest of the agents below and should continue the count in sequence.
Can anyone help create formula that would fill the numbers on the 1st column automatically for those agents that are present and has value including 0 on column 3 or 4 (stats 1 or stats 2)?
To give more idea, I'm trying to show the current total number of agents who are currently present in this situation and will count their stats, and exclude all other agents who are not present and should not be counted.
Thank you!

Sequence Two Numeric Columns
Single Cell
In cell A3, a basic not spilling formula would be...
=IF(AND(ISNUMBER(C3),ISNUMBER(D3)),MAX(A$2:A2)+1,"")
... with the condition of a string in cell A2.
Without any conditions, you could try an improved version, similar to one of David Leal's suggestions:
=IF(AND(ISNUMBER(C3),ISNUMBER(D3)),
SUM(ISNUMBER(C$3:C3)*ISNUMBER(D$3:D3)),"")
Spill
In cell A3 you could use the following:
=LET(Data1,C3:C13,Data2,D3:D13,
Data,ISNUMBER(Data1)*ISNUMBER(Data2),
IFERROR(SCAN(0,Data,LAMBDA(a,b,a+b))/Data,""))
Line1: the inputs ('constants'), the same-sized single-column ranges
Line2: the zeros and ones, where the ones present the data of interest
Line3: the formula to replace the ones with the sequence and the zeros (errors due to division by zero) with an empty string
Converted to a LAMBDA, it could look like the following:
=LAMBDA(Data1,Data2,LET(
Data,ISNUMBER(Data1)*ISNUMBER(Data2),
IFERROR(SCAN(0,Data,LAMBDA(a,b,a+b))/Data,"")))(C3:C13,D3:D13)
Since it's such a long formula, you could create your own Lambda function by using this part...
=LAMBDA(Data1,Data2,LET(
Data,ISNUMBER(Data1)*ISNUMBER(Data2),
IFERROR(SCAN(0,Data,LAMBDA(a,b,a+b))/Data,"")))
... to define a name, e.g. SeqNumeric, when in the same cell, you could use
it simply with...
=SeqNumeric(C3:C13,D3:D13)
... instead.
Now you can use the function like any other Excel function anywhere in the workbook.
The Path
F3 =ISNUMBER(C3:C13)*ISNUMBER(D3:D13) - multiply: zeros-no, ones-yes
G3 =SCAN(0,F3#,LAMBDA(a,b,a+b)) - use the 'LAMBDA' helper function 'SCAN'
H3 =G3#/F3# - divide the 'scan' result by the zeros and ones
I3 =IFERROR(H3#,"") - convert the '#DIV/0!' errors to empty strings
The translation of the SCAN part could be something like the following:
Set the initial result a to 0.
Create a new array of the size of the initial array in F3#.
Loop through each element of the initial array, write its value to b, and replace a with the sum of a+b.
Write (the accumulated) a to the current element of the new array and repeat for the remaining elements of either array.
Return the new array.
Combine all of it in a LET.
J3 =LET(Data1,C3:C13,Data2,D3:D13,
Data,ISNUMBER(Data1)*ISNUMBER(Data2),
IFERROR(SCAN(0,Data,LAMBDA(a,b,a+b))/Data,""))
Convert to LAMBDA.
K3 =LAMBDA(Data1,Data2,LET(
Data,ISNUMBER(Data1)*ISNUMBER(Data2),
IFERROR(SCAN(0,Data,LAMBDA(a,b,a+b))/Data,"")))(C3:C13,D3:D13)
Copy the first part of the LAMBDA (note how it results in a #CALC! error since no parameters are supplied)...
L3 =LAMBDA(Data1,Data2,LET(
Data,ISNUMBER(Data1)*ISNUMBER(Data2),
IFERROR(SCAN(0,Data,LAMBDA(a,b,a+b))/Data,"")))
... and select Formulas -> Name Manager -> New to create your own function and finally use it with the following:
A3 =SeqNumeric(C3:C13,D3:D13)

You can try the following in cell A1:
=LET(B, B2:B12, C, C2:C12, f, 1*ISNUMBER(B*C),seq, SEQUENCE(ROWS(B)),
MAP(seq, LAMBDA(s, IF(INDEX(f,s)=0, "",SUM(FILTER(f, (seq<=s),0))))))
Here is the output:
A non-array version, expanding down the formula would be:
=IF(ISNUMBER(B2*C2), SUM(1*ISNUMBER(B$2:B2*C$2:C2)),"")
For the array version, it counts only if both columns Stat1 and Stat2 are numeric. The name f, has a value of 1 if the condition is TRUE, otherwise is 0. The MAP does the count if the index position of the f array is not zero, otherwise returns an empty string.

I think I got it.
This is the formula that I made
=IF(COUNTIFS(D2:BE2,"*",$D$1:$BE$1,TODAY())>0,"",MAX(A1:A$4)+1)
Countif criteria 1 = if the cell contains a letter and is counted > 0 then it will return blank, otherwise it will start the count using max function. The countif criteria 2 will will return the correct value according to the date today since the excel sheet has several data daily.

Related

Is there a way to scan an entire column based on one cell in another column and pull out a value of the corresponding column?

A
B
C
D
4
1
6
5649
3
8
10
9853
5
2
7
1354
I have two worksheets, for example column A in sheet 1 and columns B-D in sheet 2.
What I want to do is to take one value in Column A, and scan both columns B and C and it is between those two values, then display the corresponding value from column D in a new worksheet.
There could be multiple matches for each of the cell in column A and if there is no match, to skip it and not have anything displayed. Is there a way to code this and somehow create a loop to do all of column A? I tried using this formula, but I think it only matches for each row and not how I want it to.
=IF(AND([PQ.xlsx]Sheet1!$A2>=[PQ.xlsx]Sheet2!$B2,[PQ.xlsx]Sheet1!$A2<[PQ.xlsx]Sheet2!$C2),[PQ.xlsx]Sheet2!$D$2,"")
How do I do this?
Thank you.
I'm not positive if I understood exactly what you intended. In this sheet, I have taken each value in A:A and checked to see if it was between any pair of values in B:C, and then returned each value from D:D where that is true. I did keep this all on a single tab for ease of demonstration, but you can easily change the references to match your own layout. I tested in Excel and then transferred to this Google Sheet, but the functions should work the same.
https://docs.google.com/spreadsheets/d/1-RR1UZC8-AVnRoj1h8JLbnXewmzyDQKuKU49Ef-1F1Y/edit#gid=0
=IFERROR(TRANSPOSE(FILTER($D$2:$D$15, ($A2>=$B$2:$B$15)*($A2<=$C$2:$C$15))), "")
So what I have done is FILTEREDed column D on the two conditions that Ax is >= B:B and <= C:C, then TRANSPOSED the result so that it lays out horizontally instead of vertically, and finally wrapped it in an error trap to avoid #CALC where there are no results returned.
I added some random data to test with. Let me know if this is what you were looking at, or if I misunderstood your intent.
SUPPORT FOR EXCEL VERSIONS WITHOUT DYNAMIC ARRAY FUNCTIONS
You can duplicate this effect with array functions in pre-dynamic array versions of Excel. This is an array function, so it has be finished with SHFT+ENTER. Put it in F2, SHFT+ENTER, and then drag it to fill F2:O15:
=IFERROR(INDEX($D$2:$D$15, SMALL(IF(($A2>=$B$2:$B$15)*($A2<=$C$2:$C$15), ROW($A$2:$A$15)-MIN(ROW($A$2:$A$15))+1), COLUMNS($F$2:F2))),"")
reformatted for easier explanation:
=IFERROR(
INDEX(
$D$2:$D$15,
SMALL(
IF(
($A2>=$B$2:$B$15)*($A2<=$C$2:$C$15),
ROW($A$2:$A$15) - MIN(ROW($A$2:$A$15))+1
),
COLUMNS($F$2:F2)
)
),
"")
From the inside out: ROW($A$2:$A$15) creates an array from 2 to 15, and MIN(ROW($A$2:$A$15))+1 scales it so that no matter which row the range starts in it will return the numbers starting from 1, so ROW($A$2:$A$15) - MIN(ROW($A$2:$A$15))+1 returns an array from 1 to 14.
We use this as the second argument in the IF clause, what to return if TRUE. For the first argument, the logical conditions, we take the same two conditions from the original formula: ($A2>=$B$2:$B$15)*($A2<=$C$2:$C$15). As before, this returns an array of true/false values. So the output of the entire IF clause is an array that consists of the row numbers where the conditions are true or FALSE where the conditions aren't met.
Take that array and pass it to SMALL. SMALL takes an array and returns the kth smallest value from the array. You'll use COLUMNS($F$2:F2) to determine k. COLUMNS returns the number of columns in the range, and since the first cell in the range reference is fixed and the second cell is dynamic, the range will expand when you drag the formula. What this will do is give you the 1st, 2nd, ... kth row numbers that contain matches, since FALSE values aren't returned by SMALL (as a matter of fact they generate an error, which is why the whole formula is wrapped in IFERROR).
Finally, we pass the range with the numbers we want to return (D2:D15 in this case) to INDEX along with the row number we got from SMALL, and INDEX will return the value from that row.
So FILTER is a lot simpler to look at, but you can get it done in an older version. This will also work in Google Sheets, and I added a second tab there with this formula, but array formulas work a little different there. Instead of using SHFT+ENTER to indicate an array formula, Sheets just wraps the formula in ARRAY_FORMULA(). Other than that, the two formulas are the same.
Since FALSE values aren't considered, it will skip those.

Using the LEFT function to extract everything before a number doesn't work well with spilled arrays

I am currently trying to extract the prefix of a store ID to be able to then generate a list of stores with only that prefix.
Cell D1 has that formula to extract the unique prefix :
=TRANSPOSE(UNIQUE(LEFT(C2#, MIN(FIND({0,1,2,3,4,5,6,7,8,9},C2#&"0123456789"))-1)))
Cell C2 has that formula to extract the unique store ids from another sheet :
=UNIQUE(INDEX('Male Shoes'!A1#,,6))
The problem is that the formula in D1 only returns the first two characters from all the unique prefixes instead of using the correct value for each prefixes.
I have setup in column I the same formula as in D1 without the TRANSPOSE() and UNIQUE() functions and remove the # to see if that would return the correct value. I dragged it down the length of the C column.
=LEFT(C2, MIN(FIND({0,1,2,3,4,5,6,7,8,9},C2&"0123456789"))-1)
In Cell J2 I put the same formula has I2 but kept the # as a control.
=LEFT(C2#, MIN(FIND({0,1,2,3,4,5,6,7,8,9},C2#&"0123456789"))-1)
I believe the MIN() function is returning the minimum for the entire array and not for each row. I haven't found how to mitigated that problem anywhere online.
In my sample data that is not a problem since all the columns in D through G gave me the lists I was expecting but as more countries get added I might end up with duplicate country prefix. (i.e.: If the prefixes get shortened to 2 characters - Germany=GE and Georgia=GE)
If it is always 2 or three a simple IF instead of FIND will work:
=TRANSPOSE(UNIQUE(LEFT(C2#,IF(ISNUMBER(--MID(C2#,3,1)),2,3))))
Edit:
If there is only one time that it switches from alpha to numeric we can use:
=TRANSPOSE(UNIQUE(LEFT(C2#,MMULT(ISNUMBER(--MID(C2#,SEQUENCE(,MAX(LEN(C2#))),1))*ISERROR(--MID("A"&C2#,SEQUENCE(,MAX(LEN(C2#))),1)),SEQUENCE(MAX(LEN(C2#))))-1)))
This does not care how many characters are in the string, only that there is only 1 time that it switches from alpha to numeric. So ABDEFGHTEV4567 will work but A3D4 will not.

i want to find count of text for a date range as criteria 1 and criteria 2 in the array

I want to count number of values (N/D) in the array (below:table: list) for criteria 1 is date range( from date and through Date) and criteria 2 is Shift A, b acros ( as shown in below table-output). I want to fill column D/N with how many times D/N occur for a date range and shift A,B,C,D?
output
From Date Through Date Shift D/N
25-May-19 26-May-19 A ?
25-May-19 26-May-19 B ?
Table- list
Dates A B C D
25-May-19 N D - -
26-May-19 N D - -
27-May-19 - D N -
INDEX(A:E,MATCH(H7:I7,A:E,0),MATCH(J7,A:E,0))
Value -?
Part of the problem you may be having is dates. Make sure your dates are excel dates and not string/text that looks like a date. Simply changing the formatting of a cell does not make it a date, it simply tells excel how to try and display the information in a cell.
Dates in excel are stored as integers and they represent the days since 1900/1/1 with that date being day 1. One of the easiest ways to test if a cell contains a date or a string is:
=ISTEXT(A1)
or
=ISNUMBER(A1)
Where A1 is the cell with the date to be tested.
If it returns TRUE for the first formula it is a string/text. FALSE means it is a number. The opposite TRUE and FALSE results apply for the second formula.
In your formula's when you have something between quotes "", it will be interpreted as a string. SO something like "<=19/05/26" mean its looking for a string less than that, not a date less than that. For doing a date comparison, either concatenate the text comparison with with a cell containing a date to compare to "<="&B2 where B2 has the date or if you want to hard code it use something like "<="&Date(19,05,26)
In order to make the following solution work, your dates all need to be stored as a number. AKA Excel serial date format.
Based on the data being layed out as per the image below, you can use COUNTIFS, INDEX, and MATCH to get the date your are looking for. I recommend find your count of D and N separately and adding them together after for a total. However if you want it in a single cell formula solution it can be achieved as well as demonstrated by the results in column N. however the formula starts to get long and can be difficult potentially read/maintain at a later date.
The core of the solution will be the COUNTIFS functions. The format of the COUNTIFS function is as follows:
COUNTIFS(Range to count 1, Criteria 1, Range to count 2, Criteria 2,...,Range to count n, Criteria n)
Let start building your formula one criteria at a time. The first Criteria will be all dates that are greater than or equal to the from date. If you only want the dates after the from date, drop the equal sign or the criteria.
=COUNTIFS($A$2:$A$4,">="&$G2,
Note the $ to lock the cell references. This is done so that when the formula gets copied, the column or row references beside the $ does not change.
Then second criteria is similar to the first except you want to grab all the dates less than or equal to the through date. Again include/drop the equal sign to suit your needs.
=COUNTIFS($A$2:$A$4,">="&$G2,$A$2:$A$4,"<="&$H2,
The next criteria will be to get all the cells that match D or N the column header. Lets just focus on D for now. The tricky part is to define which column to look in. For now lets call the column to look in XXX which will make the formula become:
=COUNTIFS($A$2:$A$4,">="&$G2,$A$2:$A$4,"<="&$H2,XXX,J$1)
OR
=COUNTIFS($A$2:$A$4,">="&$G2,$A$2:$A$4,"<="&$H2,XXX,"="&J$1)
NOTE: both formulas are the same. When no comparison operator is provided
it is taken as "=" by default.
Now in order to define XXX, INDEX and MATCH will be your friends. An important side note about INDEX is that it does not directly return the value of a cell but instead returns a cell address which in turn pulls a cell value. The basic format of INDEX is:
INDEX(Range to look in, Range's ROW to look in, Range's COLUMN to look in)
That is for a 2 dimensional range. If your range is 1 dimensional, either just a column or just a row, then only the second argument "Range's Row..." need to be provided and it represents how far down the list to go.
What gets interesting about a 2D INDEX is that when 0 is provided for ROW to look in or the Column to look in, instead of throwing an error, it instead returns all rows or columns. THIS IS IMPORTANT because you want all rows of just 1 specific column. That mean your INDEX formula is going to start to look like:
INDEX($B$2:$E$4,0,SPECIFIC COLUMN NUMBER)
So now you need to find a specific column number. That is where MATCH will be your friend. MATCH takes the following format:
MATCH(Value to find, 1D range to look in, what type of search)
You already know you are going to try and match your shift column so that will be your look up value, and the range to look in will be your column headers. The type of search you will want in this case is an exact match which is represented by 0. That means your MATCH formula will look like:
MATCH($I2,$B$1:$E$1,0)
Now to combine the various pieces, throw the MATCH formula into your INDEX and replace the "SPECIFIC COLUMN...". Your INDEX will now look like:
INDEX($B$2:$E$4,0,MATCH($I2,$B$1:$E$1,0))
And the formula above can now replace the XXX in your COUNTIFS formula and you will get:
=COUNTIFS($A$2:$A$4,">="&$G2,$A$2:$A$4,"<="&$H2,INDEX($B$2:$E$4,0,MATCH($I2,$B$1:$E$1,0)),J$1)
Place the above formula in J2 and copy the cell down and to the right.
In L2 use one of the two formulas to get the total of D and N in the date range:
=SUM(J2:K2)
OR
=J2+K2
Now to get your formula all in one cell, look at the second formula above. You can simply go to the contents of cell J2 and copy the entire formula. Then edit cell L2 and replace the cell reference for for J2 with the copied formula. Repeat the process by copy formula in K2 and replacing the reference to K2 in L2. You will wind up with a formula that looks like:
=COUNTIFS($A$2:$A$4,">="&$G2,$A$2:$A$4,"<="&$H2,INDEX($B$2:$E$4,0,MATCH($I2,$B$1:$E$1,0)),J$1)+COUNTIFS($A$2:$A$4,">="&$G2,$A$2:$A$4,"<="&$H2,INDEX($B$2:$E$4,0,MATCH($I2,$B$1:$E$1,0)),K$1)
Much longer and harder to read which is why I recommend breaking the formula down into its parts for D and N separately.
Now as an alternate method you could use SUMPRODUCT and get into array operations. Your SUMPRODUCT formula to place in I2 and copy down and right could be:
=SUMPRODUCT(($A$2:$A$4>=$G2)*($A$2:$A$4<=$H2)*(INDEX($B$2:$E$4,0,MATCH($I2,$B$1:$E$1,0))=J$1))

MAX + Left Function Excel

I am trying to get the max value of a column based on the Left function
What I am doing is the following :
These are the results I get when i write this into column C :
=MAX(LEFT(A:A, 2))
But what I truly want is to get in column C the max value of all column A not for each cell.
So the result should be in this case 90 for all rows.
What should be the formula here?
Just another option that gets entered normally:
=AGGREGATE(14,6,--LEFT($A$1:INDEX(A:A,MATCH("ZZZ",A:A)),2),1)
Array formulas will calculate the enitre referenced array. So care should be taken to limit the number of iterations to only the data set.
The $A$1:INDEX(A:A,MATCH("ZZZ",A:A)) part of the formula does that. It finds the last cell in column A with data in it and sets that as the upper bound. So in this instance the reference range is A1:A3. But, it will grow dynamically as data in Column A is added, so no need to change the formula each time data is added.
Update 2
Here is another solution which I think is better than my original (below)
=INT(SUMPRODUCT(MAX(SUBSTITUTE(A:A,"-",".")*1)))
it can be entered as normal (just Enter)
Orignal Answer
You need numbers and arrays
=MAX(IFERROR(LEFT(A:A,2)*1,0))
Let's break this down. Multiplying by turns your strings into numbers - since Left only returns a string
LEFT(A:A,2)*1
Unfortunately this method returns #Value if you multiply an empty string by 1. You will definitely have some empty strings in the range A:A so we wrap the whole thing with an IFERROR function.
IFERROR(LEFT(A:A,2)*1,0)
Now we still need excel to treat this as an array (i.e. a whole column of numbers, rather than just one number). So we put the MAX formula in and enter it with Ctrl+Shift+Enter rather than just Enter. The result is that the formula looks like this in the formula bar
{=MAX(IFERROR(LEFT(A:A,2)*1,0))}
which would return 90 in your example, as required
Update 1
If you are using Excel 2013 or later, you can also use the NUMBERVALUE function
=MAX(NUMBERVALUE(LEFT(A:A,2)))
again, enter it with Ctrl+Shift+Enter

Sort Order formula to alphabetise in Excel

I am currently drawing up a spreadsheet that will automatically remove duplicates and alphabetize a list:
I am using the COUNTIF() function in column G to create a sort order and then VLOOKUP() to find the sort in column J.
The problem I am having is that I can't seem to get my SortOrder column to function properly. At the moment it creates an index for two number 1's meaning the cell highlighted in yellow is missed out and the last entry in the sorted list is null:
If anyone can find and rectify this mistake for me I'll be very grateful as it has been driving me insane all day! Many thanks.
I'll provide my usual method for doing an automatic pulling-in of raw data into a sorted, duplicate-removed list:
Assume raw data is in column A. In column B, use this formula to increase the counter each time the row shows a non-duplicate item in column A. Hardcord B2 to be "1", and use this formula in B3 and drag down.
=if(iserror(match(A3,$A$2:A2,0)),B2+1,B2)
This takes advantage of the fact that when we refer to this row counter in our revised list, we will use the match function, which only checks for the first matching number. Then say you want your new list of data on column D (usually I do this for display purposes, so either 'group-out' [hide] columns that form the formulas, or do this on another tab). You can avoid this step, but if you are already using helper columns I usually do each step in a different column - easier to document. In column C, starting in C3 [C2 hardcoded to 1] and drag down, just have a simple counter, which error-checks to the stop at the end of your list:
=if(C2<max(B:B),C2+1," ")
Then in column D, starting at D2 and dragged down:
=iferror(index(A:A,match(C2,B:B,0)),"")
The index function is like half of the vlookup function - it pulls the result out of a given array, when you provide it with a row number. The match function is like the other half of the vlookup function - it provides you with the row number where an item appears in a given array.
Hope this helps you in the future as well.
The actual reason that this is going wrong as implied by Jeeped's comment is that you can't meaningfully compare a string to a number unless you do a conversion because they are stored differently. So COUNTIF counts numbers and text separately.
20212 will give a count of 1 because it is the only (or lowest) number.
CS10Z002 will give a count of 1 because it is the first text string in alphabetical order.
Another approach is to add the count of numbers to the count if the current cell contains text:-
=COUNTIF(INDIRECT("$D$2:$D$"&$F$3),"<="&D2)+ISTEXT(D2)*COUNT(INDIRECT("$D$2:$D$"&$F$3))
It's easier to show the result of three different conversions with some test data:-
(0) No conversion - just use COUNTIF
=COUNTIF(D$2:D$7,"<="&D2)
"999"<"abc"<"def", 999<1000
(1) Count everything as text
=SUMPRODUCT(--(D$2:D$7&""<=D2&""))
"1000"<"999"
(2) Count numbers before text
=COUNTIF(D$2:D$7,"<="&D2)+ISTEXT(D2)*COUNT(D$2:D$7)
999<1000<"999"
(3) Count everything as text but convert numbers with leading zeroes
=SUMPRODUCT(--(TEXT(D$2:D$7,"000000")<=TEXT(D2,"000000")))
"000999" = "000999", "000999"<"001000"

Resources