COUNTIFS unpredictably returns Zero - google-sheets

I am trying to grab advertising expenses for the day on the basis of country groups.
The date, and country for the record are in columns I, J and G respectively.
I am doing a VLOOKUP that references a sheet called advertising,
with the search key being a date and month together, and picking up the value column based on the country.
Then in order to average it out, I am dividing this lookup, which gives me the ad spend for a set of countries by the number of records for that date, month and country.
=(IF(OR(G4="Spain",G4="Portugal"),VLOOKUP(I4&J4,Advertising!$A$3:$AK,32,0)*IF(COUNTIFS(I$4:I,I4,J$4:J,J4,G$4:G,{"Spain","Portugal"})>0,1/COUNTIFS(I$4:I,I4,J$4:J,J4,G$4:G,{"Spain","Portugal"}),0),
IF(G4="France",VLOOKUP(I4&J4,Advertising!$A$3:$AK,33,0)*IF(COUNTIFS(I$4:I,I4,J$4:J,J4,G$4:G,{"France"})>0,1/COUNTIFS(I$4:I,I4,J$4:J,J4,G$4:G,{"France"}),0),
IF(G4="Italy",VLOOKUP(I4&J4,Advertising!$A$3:$AK,34,0)*IF(COUNTIFS(I$4:I,I4,J$4:J,J4,G$4:G,{"Italy"})>0,1/COUNTIFS(I$4:I,I4,J$4:J,J4,G$4:G,{"Italy"}),0),
IF(OR(G4="Belgium",G4="Netherlands"),VLOOKUP(I4&J4,Advertising!$A$3:$AK,35,0)*IF(COUNTIFS(I$4:I,I4,J$4:J,J4,G$4:G,{"Belgium","Netherlands"})>0,1/COUNTIFS(I$4:I,I4,J$4:J,J4,G$4:G,{"Belgium","Netherlands"}),0),
IF(G4="Sweden",VLOOKUP(I4&J4,Advertising!$A$3:$AK,36,0)*IF(COUNTIFS(I$4:I,I4,J$4:J,J4,G$4:G,{"Sweden"})>0,1/COUNTIFS(I$4:I,I4,J$4:J,J4,G$4:G,{"Sweden"}),0),
IF(G4="United Kingdom",VLOOKUP(I4&J4,Advertising!$A$3:$AK,37,0)*IF(COUNTIFS(I$4:I,I4,J$4:J,J4,G$4:G,{"United Kingdom"})>0,1/COUNTIFS(I$4:I,I4,J$4:J,J4,G$4:G,{"United Kingdom"}),0),
VLOOKUP(I4&J4,Advertising!$A$3:$AK,31,0)*IF(COUNTIFS(I$4:I,I4,J$4:J,J4,G$4:G,{"Germany","Austria","Bulgaria","Croatia","Cyprus","Australia","Denmark","Estonia","Finland","Greece","Hungary","Ireland","Latvia","Lithuania","Luxembourg","Malta","Norway","Romania","Russia","Slovakia","Slovenia","Switzerland","UAE"})>0,1/COUNTIFS(I$4:I,I4,J$4:J,J4,G$4:G,{"Germany","Austria","Bulgaria","Croatia","Cyprus","Australia","Denmark","Estonia","Finland","Greece","Hungary","Ireland","Latvia","Lithuania","Luxembourg","Malta","Norway","Romania","Russia","Slovakia","Slovenia","Switzerland","UAE"}),0)
)))))))
Unfortunately, this is returning an error for me.
As you can see, I have an IF clause to avoid division by zero.
However, I have somehow convinced myself that the error is being reurned in the averaging (i.e. division with the COUNTIFS) process, not in the VLOOKUP. I do believe my COUNTIFS are illegitimately and unexplainably returning zero.
e.g. for row 4 in the main sheet, which I have posted above,
=COUNTIFS(I$4:I,I4,J$4:J,J4,G$4:G,{"Germany","Austria","Bulgaria","Croatia","Cyprus","Australia","Denmark","Estonia","Finland","Greece","Hungary","Ireland","Latvia","Lithuania","Luxembourg","Malta","Norway","Romania","Russia","Slovakia","Slovenia","Switzerland","UAE"})
returns a zero. When I test it out with fewer countries, always including Austria, sometimes it returns zero, sometimes 1.
A sample sheet is at https://docs.google.com/spreadsheets/d/1YgK_D7FaTWtKcSts2uDiG7jlTRx2_IGrJ41wZr2qyak/edit?usp=sharing
P.S. I do not have enough reputation, but I would request one of the seniors to add "countifs" tag.

try in row 4:
=INDEX(IFNA(VLOOKUP(I4:I&"×"&J4:J,
{Advertising!B3:B&"×"&Advertising!C3:C, Advertising!B3:AK},
MATCH(G4:G, Advertising!A1:1, ), )))
update:
=INDEX(IFERROR(1/(1/(IFNA(VLOOKUP(I4:I&"×"&J4:J,
{Advertising!B3:B&"×"&Advertising!C3:C, Advertising!AE3:AK}, MATCH(IFNA(VLOOKUP(G4:G,
{{"France";"Germany";"Austria";"Bulgaria";"Croatia";"Cyprus";"Australia";"Denmark";"Estonia";"Finland";"Greece";"Hungary";"Ireland";"Latvia";"Lithuania";"Luxembourg";"Malta";"Norway";"Romania";"Russia";"Slovakia";"Slovenia";"Switzerland";"UAE";"Italy";"Belgium";"Netherlands";"Spain";"Portugal";"Sweden";"United Kingdom"},
{"France";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Italy";"Netherlands";"Netherlands";"Spain";"Spain";"Sweden";"United Kingdom"}},
2, )), Advertising!AD1:AK1, 0), ))/
COUNTIFS(I4:I&"×"&J4:J&IFNA(VLOOKUP(G4:G,
{{"France";"Germany";"Austria";"Bulgaria";"Croatia";"Cyprus";"Australia";"Denmark";"Estonia";"Finland";"Greece";"Hungary";"Ireland";"Latvia";"Lithuania";"Luxembourg";"Malta";"Norway";"Romania";"Russia";"Slovakia";"Slovenia";"Switzerland";"UAE";"Italy";"Belgium";"Netherlands";"Spain";"Portugal";"Sweden";"United Kingdom"},
{"France";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Italy";"Netherlands";"Netherlands";"Spain";"Spain";"Sweden";"United Kingdom"}},
2, )), I4:I&"×"&J4:J&IFNA(VLOOKUP(G4:G,
{{"France";"Germany";"Austria";"Bulgaria";"Croatia";"Cyprus";"Australia";"Denmark";"Estonia";"Finland";"Greece";"Hungary";"Ireland";"Latvia";"Lithuania";"Luxembourg";"Malta";"Norway";"Romania";"Russia";"Slovakia";"Slovenia";"Switzerland";"UAE";"Italy";"Belgium";"Netherlands";"Spain";"Portugal";"Sweden";"United Kingdom"},
{"France";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Germany";"Italy";"Netherlands";"Netherlands";"Spain";"Spain";"Sweden";"United Kingdom"}},
2, )))))))
or like this:
=INDEX(IFERROR(1/(1/(IFNA(VLOOKUP(I4:I&"×"&J4:J,
{Advertising!B3:B&"×"&Advertising!C3:C, Advertising!AE3:AK},
MATCH(IFNA(VLOOKUP(G4:G, Sheet3!A:B, 2, )), Advertising!AD1:AK1, 0), ))/
COUNTIFS(I4:I&"×"&J4:J&IFNA(VLOOKUP(G4:G, Sheet3!A:B, 2, )),
I4:I&"×"&J4:J&IFNA(VLOOKUP(G4:G, Sheet3!A:B, 2, )))))))

Use match(), like this:
=arrayformula(
iferror(
vlookup(
I4:I & J4:J,
{ Advertising!B3:B & Advertising!C3:C, Advertising!B3:AK },
match(G4:G, Advertising!A1:AK1, 0),
false
)
)
)
See the new Solution sheet in your sample spreadsheet. The formula is in cell P4.
Note that not all the country names in your search keys are present in the data.

Related

Google Sheets: Cell formula NOT working in ARRAYFORMULA

I've a regularly updating sheet of daily foreign exchange rates (descending order sorted).
I've written a cell formula, which works fine if I drag it to the end.
=IFNA( VLOOKUP(A2,USD_TRY!$A$2:$B$3289,2,FALSE), INDEX(USD_TRY!$A$2:$C$3289, MATCH(A2,USD_TRY!$A$2:$A$3289,-1), 3 ) )
Column A2:A is daily dates, merged from 2 different sheets of daily rates and different currencies (so it skips some dates) but it has more dates than the column USD_TRY!A2:A. This formula gets the Price rate from column USD_TRY!B2:B if the VLOOKUP() date matches but if it doesn't match then it gets the Open rate from column USD_TRY!C2:C a row before (a day after) the closest match. However, if I convert the same formula to ARRAYFORMULA() then the VLOOKUP() part works fine but the INDEX(MATCH()) part gives a wrong result of USD_TRY!C2 every time.
IF(
AND(NOT(ISBLANK(A2:A)), NOT(ISBLANK('USD_TRY Historical Data'!A2:A)), NOT(ISBLANK('USD_TRY Historical Data'!B2:B)), NOT(ISBLANK('USD_TRY Historical Data'!C2:C)) ),
ARRAYFORMULA(
IFNA(
VLOOKUP(A2:A,'USD_TRY Historical Data'!A2:B,2,FALSE),
INDEX('USD_TRY Historical Data'!A2:C, MATCH(A2:A,'USD_TRY Historical Data'!A2:A,-1), 3 ) )
)
)
}
How do I correct the ARRAYFORMULA() and is there any simpler way to get the correct results as array?
Source data:
Correct output (with cell formula):
Wrong result (with array formula):
try:
=ARRAYFORMULA(IFNA(
VLOOKUP(A2:A4, E2:F6, 2, 0),
VLOOKUP(90000-A2:A4, {90000-E2:E6, G2:G6}, 2, 1)))

Using ARRAYFORMULA to Calculate Running Total of Payables (Alternative to INDIRECT)

I use a Google Spreadsheet to keep track of the accounts payable per vendor. There is a sheet per vendor in the Spreadsheet. A simplified sheet looks like this:
When I receive a new invoice, an entry for the amount is made in the Credit column and when I release a payment, an entry for the amount is made in the Debit column. I keep track of the running total in the AC Payable column. I achieve this by using a formula in each cell of the AC Payable column (the example below is from cell E4):
=IF(
ISNUMBER(INDIRECT(ADDRESS(ROW()-1,COLUMN()))),
INDIRECT(ADDRESS(ROW()-1,COLUMN()))+C4-D4,
C4-D4
)
The logic is simple. The running total for row n is calculated by:
AC Payable(n - 1) + Credit(n) - Debit(n)
This setup works fine, except I have to drag the formula into newly added rows. Is there a way to achieve this by using ARRAYFORMULA?
PS: I have found a solution using:
= ARRAYFORMULA(
SUMIF(
ROW(C3:C),
"<="&ROW(C3:C),
C3:C)
-
SUMIF(
ROW(D3:D),
"<="&ROW(D3:D),
D3:D
)
)
I feel this is a suboptimal (The original sheet dates back to 2018. It has a lot of rows) solution since, in every row, it calculates the total of the Debit and Credit columns up to the current row and then subtracts the total of the Debit column from the total of the Credit column.
I am expecting a solution that would take advantage of the running total available in the previous row and not redo the whole calculation per row.
solution for up to 1581 rows:
=ARRAYFORMULA(QUERY(QUERY(MMULT(TRANSPOSE((SEQUENCE(COUNTA(A3:A)*2)<=
SEQUENCE(1, COUNTA(A3:A)*2))*FLATTEN(INDIRECT("C3:D"&COUNTA(A3:A)+ROW(A3)-1)*{1, -1})),
SEQUENCE(COUNTA(A3:A)*2, 1, 1, 0)), "offset 1", ), "skipping 2", ))
skills:
it's fast
it's smart
gets slower more rows you add
dies after 1581 rows
it's based on standard MMULT Running/Cumulative Total/Sum formula:
=ARRAYFORMULA(MMULT(TRANSPOSE((ROW(B1:B6)
<=TRANSPOSE(ROW(B1:B6)))*B1:B6), SIGN(B1:B6)))
but with a modification twist, because you got 2 columns to total
instead of ROW(B1:B6) we use a sequence of count of real data multiplied by two (because you got 2 columns):
SEQUENCE(COUNTA(A3:A)*2)
instead of TRANSPOSE(ROW(B1:B6)) we use again:
SEQUENCE(1, COUNTA(A3:A)*2)
combination of these pieces:
=ARRAYFORMULA(TRANSPOSE((SEQUENCE(COUNTA(A3:A)*2)<=SEQUENCE(1, COUNTA(A3:A)*2))))
will produce a matrix like:
and that's the reason why it dies with lots of rows because while you may think that if you have only 1500 rows in two columns, then formula will work only on 1500*2=3000 virtual cells, but in fact the MMULT formula processes (1500*2)*(1500*2)=9000000 virtual cells. still, it's worth to note, that this MMULT fx is great if deployed on a small scale.
next, instead of *B1:B6 we use:
*FLATTEN(INDIRECT("C3:D"&COUNTA(A3:A)+ROW(A3)-1)*{1, -1}))
eg. with INDIRECT we take only "valid" range of C3:D which is in your example sheet just C3:D5 and we multiply C column by 1 and D column by -1 to simulate subtraction and then we FLATTEN both columns into one single column. the part +ROW(A3)-1 is just an offset because you start from row 3
and the last part of standard RT fx - SIGN(B1:B6) is replaced with one column full of ones:
SEQUENCE(COUNTA(A3:A)*2, 1, 1, 0)
then we offset the output with inner QUERY by 1 because we are interested in a totals after subtraction and finally we use skipping 2 which means that we filter out every second value - again, we are interested in totals after subtraction of D column.
solution for more than 1581 rows:
=ARRAYFORMULA(
SUMIF(SEQUENCE(COUNTA(A3:A)), "<="&SEQUENCE(COUNTA(A3:A)), INDIRECT("C3:C"&COUNTA(A3:A)))-
SUMIF(SEQUENCE(COUNTA(A3:A)), "<="&SEQUENCE(COUNTA(A3:A)), INDIRECT("D3:D"&COUNTA(A3:A))))
skills:
supports more rows
looks less smart
sadly the third argument of SUMIF always needs to be a range
gets slower with more rows
it will get sick if you feed it with 10000 rows
it may kill off your sheet with 11000+ rows
Here'a modification of Ben Collins' running total formula
=ARRAYFORMULA(
IF(ISBLANK(A2:A),,
MMULT(TRANSPOSE((ROW(C2:C)<=TRANSPOSE(ROW(C2:C)))*C2:C),SIGN(C2:C))-
MMULT(TRANSPOSE((ROW(D2:D)<=TRANSPOSE(ROW(D2:D)))*D2:D),SIGN(D2:D))))
yet another alternative to MMULT:
=INDEX(QUERY(FLATTEN(QUERY(QUERY(TRANSPOSE(QUERY(QUERY(TRANSPOSE(
(SEQUENCE(COUNTA(A3:A)*2)<=SEQUENCE(1, COUNTA(A3:A)*2))*
FLATTEN(INDIRECT("C3:D"&COUNTA(A3:A)+ROW(A3)-1)*{1, -1})),
"offset 1", ), "skipping 2", )), "select "&QUERY(
"sum(Col"&SEQUENCE(COUNTA(A3:A))&"),",, 9^9)&"' '"),
"offset 1", )), "where Col1 is not null", ))
but again, LTE (<=) limitation of 10M cells won't let you use more than 1581 rows in your case or 3162 rows in the standard cumulative sum case
(1581 rows * 2 columns) raised on 2nd power < 10 million cells
(1581*2)^2 = 9998244

Why my ArrayFormula is giving error? How do I correct it? (I'm not looking for another Arrayformula as solutions!)

I wanted a ArrayFormula at C1 which gives the required result as shown.
Entry sheet:
(Column C is my required column)
Date Entered is the date when the Name is Assigned a group i.e. a, b, c, d, e, f
Criteria:
The value of count is purely on basis of Date Entered (if john is assigned a on lowest date(10-Jun) then count value is 1, if rose is assigned a on 2nd lowest date(17-Jun) then count value is 2).
The value of count does not change even when the data is sorted in any manner because Date Entered column values is always permanent & does not change.
New entry date could be any date not necessarily highest date (If a new entry with name Rydu is assigned a on 9-Jun then the it's count value will become 1, then john's (10-Jun) will become 2 and so on)
Example:
After I sort the data in any random order say like this:
Random ordered sheet:
(Count value remains permanent)
And when I do New entries in between (Row 4th & 14th) and after last row (Row 17th):
Random Ordered sheet:
(Doesn't matter where I do)
I already got a ArrayFormula which gives the required result:
={"AF Formula1"; ArrayFormula(IF(B2:B="", "", COUNTIFS(B$2:B, "="&B2:B, D$2:D, <"&D2:D)+1))}
I'm not looking for another Arrayformula as solutions. What I want is to know what is wrong in my ArrayFormula? and how do I correct it?
I tried to figure my own ArrayFormula but it's not working:
I got Formula for each cell:
=RANK($D2,FILTER($D$2:$D, $B$2:$B=$B2),1)
I figured out Filter doesn't work with ArrayFormula so I had to take a different approach.
I took help from my previous question answer (Arrayformula at H3) which was similar since in both cases each cell FILTER formula returns more than 1 value. (It was actually answered by player0)
Using the same technique I came up with this Formula which works absolutely fine :
=RANK($D2, ARRAYFORMULA(TRANSPOSE(SPLIT(VLOOKUP($B2, SUBSTITUTE(TRIM(SPLIT(FLATTEN(QUERY(QUERY({$B:$B&"×", $D:$D}, "SELECT MAX(Col2) WHERE Col2 IS NOT NULL GROUP BY Col2 PIVOT Col1", 1),, 9^9)), "×")), " ", ","), 2, 0), ","))), 1)
Now when I tried converting it to ArrayFormula:
($D2 to $D2:$D & $B2 to $B2:$B)
=ARRAYFORMULA(RANK($D2:$D,TRANSPOSE(SPLIT(VLOOKUP($B2:$B, SUBSTITUTE(TRIM(SPLIT(FLATTEN(QUERY(QUERY({$B:$B&"×", $D:$D}, "SELECT MAX(Col2) WHERE Col2 IS NOT NULL GROUP BY Col2 PIVOT Col1", 1),, 9^9)), "×")), " ", ","), 2, 0), ",")), 1))
It gives me an error "Did not find value '' in VLOOKUP evaluation", I figured out that the problem is only in VLOOKUP when I change $B2 to $B2:$B.
I'm sure VLOOKUP works with ArrayFormula, I fail to understand where my formula is going wrong! Please help me correct my ArrayFormula.
Here is the editable sheet link
if I understand correctly, you are trying to "rank" B column based on D column dates in such way that dates are in theoretical ascending order so if you randomize your dataset, the "rank" of each entry would stay same and not change based on the randomness you introduce.
therefore the correct formula would be:
={"fx"; INDEX(IFNA(VLOOKUP(B2:B&D2:D,
{INDEX(SORT({B2:B&D2:D, D2:D}, 2, 1),,1),
IFERROR(1/(1/COUNTIFS(
INDEX(SORT(B2:D, 3, 1),,1),
INDEX(SORT(B2:D, 3, 1),,1), ROW(B2:B), "<="&ROW(B2:B))))}, 2, 0)))}
{"fx"; ...} array of 2 tables (header & actual table) under each other eg. ;
outer shorter INDEX or longer ARRAYFORMULA (doesnt matter which one) is needed coz we are processing an array
IFNA for removing possible #N/A errors from VLOOKUP function when VLOOKUP fails to find a match
we VLOOKUP joint B and D column B2:B&D2:D in our virtual table {} and returning second 2 column if there is an exact match 0
our virtual table {INDEX(SORT({B2:B&D2:D, D2:D}, 2, 1),,1), ...} we VLOOKUP from is constructed with 2 columns next to each other eg. ,
we are getting the first column by creating an array of 2 columns {B2:B&D2:D, D2:D} next to each other where we SORT this array by date/2nd column 2, in ascending order 1 but all we need after sorting is the 1st column so we use INDEX where we bring all rows ,, and the first column 1
now lets take a look on how we getting the 2nd column of our virtual table by using COUNTIFS which will mimic the "rank"
IFERROR(1/(1/ is used to remove all zero values from the output (all empty rows would have 0 in it as the "rank")
under COUNTIFS we put 2 pairs of arguments: "if column is qual to column" and "if row is larger or equal to next row increment it by 1" ROW(B2:B), "<="&ROW(B2:B))
for "if column is qual to column" we do this twice and use range B2:D and sort it by date/3rd column 3 in ascending order 1 and of this we again need only the 1st column so we INDEX it and return all rows ,, and first column 1
with this formula you can add, remove or randomize your dataset and you will always get the right value for each of your rows
as for why your formula doesnt work... to not get #N/A error for vlookup you would need to define the end row of the range but still, the result wont be as you would expect coz formula is not the right one for this job.
as mentioned there are functions that are not supported under AF like SUM,AND,OR and then there are also functions which work but in a different way like IFS or with some limitations like SPLIT,GOOGLEFINANCE,etc.
I have answered you on the tab in your shared sheet called My Practice thusly:
You cannot split a two column array as you have attempted to do in cell CI2. That is why your formula does not work. You can only split a ONE column array.
I understand you are trying to learn, but attempting to use complicated formulas like that is going to make it harder I'm afraid.

ARRAY formula to find last row to contain value in Google Sheets

I have a Google Sheet that is populated automatically via Zapier integration. For each new row added, I need to evaluate a given cell (Shipper Name) to find last instance of Shipper Name in prior rows, and if so, return Row# for the last entry.
Example Data Sheet
I am trying to create a formula that simply looks at name in new row and returns the number of the most recent row with that name.
Formula needs to run as an Array formula so that the data auto populates with each new row added to the Sheet.
I have tried to use this formula, but when refactored as Array formula, it doesn't populate new values for new rows, it just repeats the first value for all rows.
From Row J:
=sumproduct(max(row(A$1:A3)*(F4=F$1:F3)))
I need this formula refactored to be an Array formula that auto populates all the cells below it.
I have tried this version, but it doesn't work:
=ArrayFormula(IF(ISBLANK($A2:$A),"",sumproduct(max(row(A$1:A3)*($F4:$F=F$1:F3))))
A script (custom function maybe?) would be better.
Solution 1
Below is a formula you can place into the header (put in in J1, remove everything below).
It works much faster than the second solution and has no N² size restriction. Also it works with empty shippers (& "♥" is for those empty ones): as long as A:A column has some value it will not be ignored.
={
"Row of Last Entry";
ARRAYFORMULA(
IF(
A2:A = "",
"",
VLOOKUP(
ROW(F2:F)
+ VLOOKUP(
F2:F & "♥",
{
UNIQUE(F2:F & "♥"),
SEQUENCE(ROWS(UNIQUE(F2:F)))
* POWER(10, INT(LOG10(ROWS(F:F))) + 1)
},
2,
0
),
SORT(
{
ROW(F2:F) + 1
+ VLOOKUP(
F2:F & "♥",
{
UNIQUE(F2:F & "♥"),
SEQUENCE(ROWS(UNIQUE(F2:F)))
* POWER(10, INT(LOG10(ROWS(F:F))) + 1)
},
2,
0
),
ROW(F2:F);
{
SEQUENCE(ROWS(UNIQUE(F2:F)))
* POWER(10, INT(LOG10(ROWS(F:F))) + 1),
SEQUENCE(ROWS(UNIQUE(F2:F)), 1, 0, 0)
}
},
1,
1
),
2,
1
)
)
)
}
Details on how it works
For every row we use VLOOKUP to search for a special number in a sorted virtual range to get the row number of the previous entry matching current.
A special number for a row is constructed like this: we get a sequential number for the current entry among unique entries and append to it current row number.
The right part (row number) of the resulting special numbers must be aligned between them. If the entry has sequential number 13 and the row number is 1234 and there are 100500 rows, then the number must be 13001234. 001234 is the aligned right part.
Alignment is done by multiplying a sequential number by 10 to the power of (log10(total number of rows) + 1), gives us 13000000 (from the example above). This approach is used to avoid using LEN and TEXT - working with numbers is faster then working with strings.
Virtual range has almost the same special numbers in the first column and original row numbers in the second.
Almost the same special numbers: they just increased by 1, so VLOOKUP will stop at most one step before the number corresponding to the current string.
Also virtual range has some special rows (added at the bottom before sorting) which have all 0's as the right part of their special numbers (1st column) and 0 for the row number (2nd column). That is done so VLOOKUP will find it for the first occurrence of the entry.
Virtual range is sorted, so we could use is_sorted parameter of the outer VLOOKUP set to 1: that will result in the last match that is less or equal to the number being looked for.
& "♥" are appended to the entries, so that empty entries also will be found by VLOOKUP.
Solution 2 - slow and has restrictions
But for some small enough number of rows this formula works (put in in J1, remove everything below):
={
"Row of Last Entry";
ARRAYFORMULA(
REGEXEXTRACT(
TRANSPOSE(QUERY(TRANSPOSE(
IF(
(FILTER(ROW(F2:F), F2:F <> "") > TRANSPOSE(FILTER(ROW(F2:F), F2:F <> "")))
* (FILTER(F2:F, F2:F <> "") = TRANSPOSE(FILTER(F2:F, F2:F <> ""))),
TRANSPOSE(FILTER(ROW(F2:F), F2:F <> "")),
""
)
), "", ROWS(FILTER(F2:F, F2:F <> "")))),
"(\d*)\s*$"
)
)
}
But there is a problem. The virtual range inside of the formula is of size N², where N is the number of rows. For current 1253 rows it works. But there is a limit after which it will throw an error of a range being too large.
That is the reason to use FILTER(...) and not just F2:F.
Here is a significantly simpler way to get at the information you're interested in. (I think.) I'm mostly guessing about what you want because your question wasn't really about what you want, but rather about how to get something that you think would help you get what you want. This is an example of an XY problem. I attempted to guess based on experience at what you're really after.
This editable sheet contains just 3 formulas. 2 on the raw data sheet and one in a new tab called "analysis."
The first formula on the Raw data tab extracts a properly formatted timestamp using a combination of MMULT and SPLIT functions and looks like this:
=ARRAYFORMulA({"Good Timestamp";IF(A2:A="",,MMULT(N(IFERROR(SPLIT(A2:A,"T"))),{1;1}))})
The second formula finds the amount of time since the previous timestamp for that Shipper. and subtracts it from the current timestamp thereby giving you the time between timestamps. However, it only does this if the time is less than 200 minutes. IF it is more than 200 minutes, it assumes that was a different shift for that shipper. It looks like this and uses a combination of LOOKUP() and SUBSTITUTE() to make sure it's pulling the correct timestamps. Obviously, you can find and change the 200 value to something more appropriate if it makes sense.
=ARRAYFORMULA({"Minutes/Order";IF(A2:A="",,IF(IFERROR((G2:G-1*SUBSTITUTE(LOOKUP(F2:F&G2:G-0.00001,SORT(F2:F&G2:G)),F2:F,""))*24*60)>200,,IFERROR((G2:G-1*SUBSTITUTE(LOOKUP(F2:F&G2:G-0.00001,SORT(F2:F&G2:G)),F2:F,""))*(24*60))))})
The third formula, on the tab called analysis uses query to show the average minutes per order and the number of orders per hour that each shipper is processing. It looks like this:
=QUERY({'Sample Data'!F:I},"Select Col1,AVG(Col3),COUNT(Col3)/(SUM(Col3)/60) where Col3 is not null group by Col1 label COUNT(Col3)/(SUM(Col3)/60)'Orders/ hour',AVG(Col3)'Minutes/ Order'")
Hopefully I've guessed correctly at your real goals. Always do your best to explain what they are rather than asking for only a small portion that you think will help you get to the answer. You can end up overcomplicating your process without realizing it.

Google spreadsheet creating unique IDs from informations in different columns

I want to create unique ID's for every items in a Google spreadsheet. This ID has to reflect informations contained in 2 columns. I made a simpler version of my data and joined it as an image WhereImAt. As you can see in the first column, I want people to be able to identify the "city", the "type" for each item in the spreadsheet and a number which make the entry unique.
The actual spreadsheet as more than 2k items in it. The column "city" has 19 possible entries and the "type" has 12.
For the moment the only formulas I can think of is "If()", but with so many variables, it looks impossible or way too complex. I'm sure there is something more efficient...
Can anyone think of a better way to achieve my goal?
Since the Cities will probably not all start with a unique character, you would need a table to look up the code for the city. Since you have a limited number of Cities and Types, you can use a table for each to validate the entries and look up the code. Assuming a table (sheet/tab) for each you could have a sheet called City and one called Type. City has the City Names listed in column A, starting at A2, and the associated Code in column B. Type has the Type listed in column A starting at cell A2, and the associated Code in column B. Both sheets use row 1 as a Header row.
So in your sheet, in cell B2, place this formula:
=CONCATENATE( VLOOKUP(C2, City!A2:B, 2, FALSE), "_", VLOOKUP(D2, Type!A2:B, 2, FALSE))
It will look up the City Name and the Type, returning the Code for each, and making a string which is CityCode_TypeCode.
Since you have many rows of data, you do not want to copy this formula for every row. This is where ARRAYFORMULA comes in. Unfortunately we cannot use CONCATENATE in an ARRAYFORMULA function, but there is an easy way around that. The more difficult part is using VLOOKUP, but with the trick used here, we can make that work. We will combine the strings using & and add an array to the third item of the VLOOKUP to get these to work. Last, I will use a little trick to place this in row 1 and still apply a header. For your Column B, you would place this in B1, and make sure the rest of the column is empty:
=ARRAYFORMULA(IF(ROW(C1:C) = 1, "ID", IF(ISBLANK(C1:C),, VLOOKUP(C1:C, City!A2:B, 2 * SIGN( ROW( C1:C ) ), FALSE) & "_" & VLOOKUP(D1:D, Type!A2:B, 2 * SIGN( ROW( D1:D ) ), FALSE))))
This only gets us to where you are currently with only one formula. To get to teh last step, I need assume the data will not be sorted, have rows inserted or deleted, etc. Is this one rule can be followed, the item in row 3 will ALWAYS be in row 3, we can get you to the last step using the Row Number by adding
TEXT(ROW(A1:A)-1, "0000)
to the mix to get a 4 digit number representing 1 less than the row so that our numbers start at 0001 So in your file, in cell A1, place this with nothing in the rest of the column:
=ARRAYFORMULA(IF(ROW(C1:C) = 1, "ID", IF(ISBLANK(C1:C),, VLOOKUP(C1:C, City!A2:B, 2 * SIGN( ROW( C1:C ) ), FALSE) & "_" & VLOOKUP(D1:D, Type!A2:B, 2 * SIGN( ROW( D1:D ) ), FALSE) & "_" & TEXT(ROW(A1:A)-1, "0000"))))

Resources