Excel Function to split cells - excel

If we do not use VBA, any methods can be used to split the following cell in excel?
Please advise the methods for splitting text "ParisFrancePeter" to 3 separate words "Paris" "France" and "Peter".

'first word
=REPLACE(A1, AGGREGATE(15, 7, ROW(2:99)/(CODE(MID(A1, ROW(2:99), 1))<=90), 1), LEN(A1), "")
'middle word
=MID(A1, AGGREGATE(15, 7, ROW(2:99)/(CODE(MID(A1, ROW(2:99), 1))<=90), 1), LEN(A1)-AGGREGATE(14, 7, ROW(2:99)/(CODE(MID(A1, ROW(2:99), 1))<=90), 1)+2)
'last word
=REPLACE(A1, 1, AGGREGATE(14, 7, ROW(2:99)/(CODE(MID(A1, ROW(2:99), 1))<=90), 1)-1, "")

If you also have other than three words to split, then, with your original string in A1, enter the formula below in B1 and fill right as far as required:
=IFERROR(MID($A1,IFERROR(AGGREGATE(15,6,1/((CODE(MID($A1,seq,1))>=65)*(CODE(MID($A1,seq,1))<=90))*(seq),COLUMNS($A:A)),""),IF(IFERROR(AGGREGATE(15,6,1/((CODE(MID($A1,seq,1))>=65)*(CODE(MID($A1,seq,1))<=90))*(seq),COLUMNS($A:B)),"")="",99,IFERROR(AGGREGATE(15,6,1/((CODE(MID($A1,seq,1))>=65)*(CODE(MID($A1,seq,1))<=90))*(seq),COLUMNS($A:B)),"")-IFERROR(AGGREGATE(15,6,1/((CODE(MID($A1,seq,1))>=65)*(CODE(MID($A1,seq,1))<=90))*(seq),COLUMNS($A:A)),""))),"")
where seq is a Named Formula that generates an array of numbers {1...255} and refers to:
=ROW(INDEX($1:$65535,1,1):INDEX($1:$65535,255,1))
The code will return the starting point of each Upper Case letter, and then uses the MID function to return the substring between that and the next upper case letter. Then there is some error checking.

Related

Excel formula Compare Data to previous 20 entries for change

I have an excel table for raw material offloads. All get tested, but some don't get offloaded right away. I'm trying to create a formula that looks at the future 20 entries for the same railcar and see if it changed from "N" to "Y" for offload.
Here's what my data looks like:
CAR # Offloaded?
CTCX733450 N
CTCX733450 Y
GATX207935 N
CTCX733472 Y
GATX207923 N
GATX207935 Y
GATX207923 Y
I've tried COUNTIF functions and IF functions. I can detect the duplicate railcars, but can't correspond the Y and N with the railcar.
Any help is appreciated.
You can use COUNTIFS to check multiple columns at once. For example
=COUNTIFS(A3:A22, A2, B3:B22, "Y")
This will take the value in cell A2 (CTCX733450), then look at the following 20 rows (Rows 3-22) to see how many time Column A is that value and Column B is "Y". If it is greater than 0, then one of the next 20 instances of that Railcar has been Offloaded.
Notably, this "the next 20 rows", and not "the next 20 entries for the same railcar". For that, we would need to use AGGREGATE and INDEX to find the 20th time that railcar next appears, which will be the final row we check.
For the time being, we will substitute for this row value with ROW_VALUE. This then lets us rewrite our formula using INDEX, as follows:
=COUNTIFS(A3:INDEX(A:A, ROW_VALUE), A2, B3:INDEX(B:B, ROW_VALUE), "Y")
Simple enough! The tricky bit, though, is now working out what value we should have for ROW_VALUE. This is where the AGGREGATE comes in.
You see, we can use AGGREGATE to get the kth (fourth parameter) smallest (First parameter = 15) non-error value (Second parameter = 6) from a list of values (third parameter). We can also make a list of Rows where column A is the same as the value in A2, by using #DIV0! (divide by zero) errors, and the fact that TRUE/FALSE can be treated as 1/0
AGGREGATE(15, 6, Row(A:A)/(A:A=A2), k)
In your case, we want k to be 20 + how many copies of railcar we already have. We can count how many copies of the railcar have passed us by using COUNTIF, so long as we lock one end to the first row:
AGGREGATE(15, 6, Row(A:A)/(A:A=A2), 20+COUNTIF(A$1:A2, A2))
Now, in theory we could shove that in as our ROW_VALUE. In practice, I can immediately see 2 big problems with it. The first, working on Whole Columns is slow. Second, and more important: What happens if there are less than 20 copies of the railcar remaining? You get a #NUM! error, that's what.
We can fix both of these issues with COUNTA (assuming that there are no rows without railcar numbers). For the first one, we will use INDEX again:
AGGREGATE(15, 6, Row(A$1:INDEX(A:A, COUNTA(A:A)))/(A$1:INDEX(A:A, COUNTA(A:A))=A2), 20+COUNTIF(A$1:A2, A2))
Alternatively, you can rearrange this to get rid of the COUNTIF at the end, by starting your Range on the next row, and just looking for the 20th number:
AGGREGATE(15, 6, Row(A3:INDEX(A:A, COUNTA(A:A)))/(A3:INDEX(A:A, COUNTA(A:A))=A2), 20)
For the second issue, we'll use IFERROR. This is a simple function - it just says "Return this value, unless it is an error - then, use this other value instead". Our "other value" will be the COUNTA of Column A, which should give us the last row in your list of Railcars:
IFERROR(AGGREGATE(15, 6, Row(A3:INDEX(A:A, COUNTA(A:A)))/(A3:INDEX(A:A, COUNTA(A:A))=A2), 20),COUNTA(A:A))
This then gives us our ROW_VALUE, which we can plug into our other earlier COUNTIFS:
=COUNTIFS(A3:INDEX(A:A, IFERROR(AGGREGATE(15, 6, Row(A3:INDEX(A:A, COUNTA(A:A)))/(A3:INDEX(A:A, COUNTA(A:A))=A2), 20),COUNTA(A:A))), A2, B3:INDEX(B:B, IFERROR(AGGREGATE(15, 6, Row(A3:INDEX(A:A, COUNTA(A:A)))/(A3:INDEX(A:A, COUNTA(A:A))=A2), 20),COUNTA(A:A))), "Y")
Finally, and optionally: we can make a slight boost in calculation time by working out if the AGGREGATE will error before it does so, by checking if there are at least 20 more entries for the Railcar. This also replaces the IFERROR with an IF statement, but makes the whole equation longer:
=COUNTIFS(A3:INDEX(A:A, IF(COUNTIF(A3:INDEX(A:A, COUNTA(A:A)),A2)<20, COUNTA(A:A), AGGREGATE(15, 6, Row(A3:INDEX(A:A, COUNTA(A:A)))/(A3:INDEX(A:A, COUNTA(A:A))=A2), 20))), A2, B3:INDEX(B:B, IF(COUNTIF(A3:INDEX(A:A, COUNTA(A:A)),A2)<20, COUNTA(A:A), AGGREGATE(15, 6, Row(A3:INDEX(A:A, COUNTA(A:A)))/(A3:INDEX(A:A, COUNTA(A:A))=A2), 20))), "Y")
We have replaced this ROW_VALUE
IFERROR(AGGREGATE(15, 6, Row(A3:INDEX(A:A, COUNTA(A:A)))/(A3:INDEX(A:A, COUNTA(A:A))=A2), 20),COUNTA(A:A))
with this one instead
IF(COUNTIF(A3:INDEX(A:A, COUNTA(A:A)),A2)<20, COUNTA(A:A), AGGREGATE(15, 6, Row(A3:INDEX(A:A, COUNTA(A:A)))/(A3:INDEX(A:A, COUNTA(A:A))=A2), 20))

Excel : How to apply a criterion to each cell in an array?

So in the example above, I would like to extract all cells that contain "A" as the first letter(and length=9, though it does not matter). Now I am able to run the function for one cell, but I want to run it as an array formula so that I do not have to drag down 1000 cells every time. Below is my code:
=IFERROR(INDEX($A$1:$A$3, IF(AND(LEFT(A2,1)="A", LEN(A2)=9), ROW($A$1:$A$3),"")),"")
The problem here is that when I enter the code with "Ctrl + Shift + Enter", the criteria would be only confined to A2, which is the cell address I manually entered. Is there anyway to check for every single cell without having to drag down WITHOUT USING VBA? I know using VBA would make it a lot easier, but I just want to understand the basics of Excel further.
Try,
=iferror(index(a:a, aggregate(15, 7, row(a:a)/(left(a$1:index(a:a, match("zzz", a:a)))="a"), row(1:1))), text(,))
'with 9 length criteria
=iferror(index(a:a, aggregate(15, 7, row(a:a)/((left(a$1:index(a:a, match("zzz", a:a)))="a")*(len(a$1:index(a:a, match("zzz", a:a)))=9)), row(1:1))), text(,))
Fill down as necessary.
If you only want the single left-most character from a string of text, you do not have to supply a 1; you can omit the number of characters argument.

Search for two consecutive rows with same data in Excel

I have a database of about 100 columns with similar data to from COL A to COL H.
I use the formula in COL J to search in a column for two consecutive rows with "-" and mark the second row as a double as you can see on J16 and J32.
This method is time consuming because I do often search for different columns and have to change the formula each time.
I would like something like N3. Entering the column ID and when I hit enter I will get automatically the count of rows with two consecutive "-" and also I would like to increase to search for triples and quadruples.
Any help will be appreciate.
Formula on J2:
=IF(AND(OR(F2=F1,F1="-"),F2="-"),"double","")
image here
In N5 to count doubles,
=COUNTIFS(INDEX(A:H, 2, CODE(UPPER(N3))-64):INDEX(A:H, MATCH("zzz", INDEX(A:H, , CODE(UPPER(N3))-64)), CODE(UPPER(N3))-64), "-",
INDEX(A:H, 3, CODE(UPPER(N3))-64):INDEX(A:H, MATCH("zzz", INDEX(A:H, , CODE(UPPER(N3))-64))+1, CODE(UPPER(N3))-64), "-")
This is the dynamic equivalent of using,
=COUNTIFS(G2:G20, "-", G3:G21, "-")
In N6 to count triples,
=COUNTIFS(INDEX(A:H, 2, CODE(UPPER(N3))-64):INDEX(A:H, MATCH("zzz", INDEX(A:H, , CODE(UPPER(N3))-64)), CODE(UPPER(N3))-64), "-",
INDEX(A:H, 3, CODE(UPPER(N3))-64):INDEX(A:H, MATCH("zzz", INDEX(A:H, , CODE(UPPER(N3))-64))+1, CODE(UPPER(N3))-64), "-",
INDEX(A:H, 4, CODE(UPPER(N3))-64):INDEX(A:H, MATCH("zzz", INDEX(A:H, , CODE(UPPER(N3))-64))+2, CODE(UPPER(N3))-64), "-")
In N7 to count quads,
=COUNTIFS(INDEX(A:H, 2, CODE(UPPER(N3))-64):INDEX(A:H, MATCH("zzz", INDEX(A:H, , CODE(UPPER(N3))-64)), CODE(UPPER(N3))-64), "-",
INDEX(A:H, 3, CODE(UPPER(N3))-64):INDEX(A:H, MATCH("zzz", INDEX(A:H, , CODE(UPPER(N3))-64))+1, CODE(UPPER(N3))-64), "-",
INDEX(A:H, 4, CODE(UPPER(N3))-64):INDEX(A:H, MATCH("zzz", INDEX(A:H, , CODE(UPPER(N3))-64))+2, CODE(UPPER(N3))-64), "-",
INDEX(A:H, 5, CODE(UPPER(N3))-64):INDEX(A:H, MATCH("zzz", INDEX(A:H, , CODE(UPPER(N3))-64))+3, CODE(UPPER(N3))-64), "-")
If you require quints, you should be able to get the idea from those.
You want to use your column entry in cell N3. You can do this using the indirect function. Just change the formula in cell J2 from this:
=IF(AND(OR(F2=F1,F1="-"),F2="-"),"double","")
...to this:
=IF(AND(INDIRECT(N$3&ROW())="-",INDIRECT(N$3&ROW()-1)="-"),"double","")
You can catch triples and quadruples in the same way, try this formula ...it'll only work from row 4 onwards, and the results may feel messy, depending on what you need:
=IF(AND(INDIRECT(N$3&ROW()-1)="-",INDIRECT(N$3&ROW())="-"),IF(AND(INDIRECT(N$3&ROW()-2)="-",INDIRECT(N$3&ROW()-1)="-",INDIRECT(N$3&ROW())="-"),IF(AND(INDIRECT(N$3&ROW()-3)="-",INDIRECT(N$3&ROW()-2)="-",INDIRECT(N$3&ROW()-1)="-",INDIRECT(N$3&ROW())="-"),"quadruple","triple"),"double"),"")
With reference to the figure at the bottom, there are:
Helper cells N1:N2 and N9:N19, whose contents helps the formulas you need being more concise.
See below the explanation and formulas for these.
Cells with the formulas you need, using SUMPRODUCT combined with some form of dynamic referencing.
Cells N5:N7
give the result you want, but with fixed references. These are
N5: =SUMPRODUCT(($G$2:$G$21="-")*($G$3:$G$22="-"))
N6: =SUMPRODUCT(($G$2:$G$20="-")*($G$3:$G$21="-")*($G$4:$G$22="-"))
N7: =SUMPRODUCT(($G$2:$G$19="-")*($G$3:$G$20="-")*($G$4:$G$21="-")*($G$5:$G$22="-"))
You can grasp the systematics.
Cells O5:O7
give the same result, using INDIRECT instead of fixed references (option #1 for what you need, see this). These are
O5: =SUMPRODUCT(
(INDIRECT($N$3&$N$9):INDIRECT($N$3&($N$10-1))="-")
*(INDIRECT($N$3&($N$9+1)):INDIRECT($N$3&$N$10)="-")
)
O6: =SUMPRODUCT(
(INDIRECT($N$3&$N$9):INDIRECT($N$3&($N$10-2))="-")
*(INDIRECT($N$3&($N$9+1)):INDIRECT($N$3&($N$10-1))="-")
*(INDIRECT($N$3&($N$9+2)):INDIRECT($N$3&$N$10)="-")
)
You can grasp the systematics and write the formula for cell O7.
Cells P5:P7
give the same result, using OFFSET instead of fixed references (option #2 for what you need, see this, this, or this). These are
P5: =SUMPRODUCT(
(OFFSET($A$1,$N$12,$N$14):OFFSET($A$1,$N$13-1,$N$14)="-")
*(OFFSET($A$1,$N$12+1,$N$14):OFFSET($A$1,$N$13,$N$14)="-")
)
P6: =SUMPRODUCT(
(OFFSET($A$1,$N$12,$N$14):OFFSET($A$1,$N$13-2,$N$14)="-")
*(OFFSET($A$1,$N$12+1,$N$14):OFFSET($A$1,$N$13-1,$N$14)="-")
*(OFFSET($A$1,$N$12+2,$N$14):OFFSET($A$1,$N$13,$N$14)="-")
)
You can grasp the systematics and write the formula for cell P7.
There are likely other options combining INDIRECT and OFFSET (see this). An option using INDEX (although likely not the only variant) was covered by Jeeped.
Note on helper cells:
I suggest having helper cells, and this applies to other answers posted here as well.
Of course you may move these cells around, adjusting the corresponding formulas.
The only non trivial formula here is for cell N11, =COLUMN(INDIRECT($N$3&"1")) (see this or this).
Cell N19 may be useful if you are going to use INDEX.

Convert date into number

I have a table as under
AAA 28/01/2016
I tried many option like changing format. Datevalue, Datevalue(text...) functions but the date is not being converted into number.
You got AAA 28/01/2016 in either one cell or two and want to make that text into an actual date or even a number.
        
The formulas in C1:C2 are,
=DATE(RIGHT(B1, 4), MID(B1, 8, 2), MID(B1, 5, 2)) ◄ C1
=DATE(RIGHT(B2, 4), MID(B2, 4, 2), MID(B2, 1, 2)) ◄ C2
Format however you want after you have made the text-to-date conversion. To avoid ambiguity, the above uses dd-mmm-yyyy_) . A true number would be 0 to show 42,397. Note that text (by default) is left-aligned in the cell while dates and numbers are right-aligned.
Use below function.
=TEXT(A1,0)
Simply put:
=--A1
Then format the cell as you want. The -- will change it to a number.

MATCH reverse order

In an excel sheet, I have from A1 to A6:
1, 2, 4, 6, 8, 9
I would like, using MATCH function, to retrieve the smallest interval that contains 5. Here, 4 and 6.
I can easily use the MATCH and INDEX function to find 4, but I can't find a way to find the 6.
How can I reverse the order of the Array in the MATCH function?
You still can use the composition of INDEX and MATCH by using #ExcelHero add one trick but you need to make sure the matched offset doesn't overflow your index. In many use cases, you could also protect your match against an underflow. Of course, we wouldn't need all this if MATCH didn't request a reverse (descending) order for the -1 (Greater than) match type argument or if Excel provided a formula for reversing an array.
My suggestion is to use the following formula for the MATCH
part:
=IF(N19 < INDEX(lookup_range, 1), 1, MIN(ROWS(lookup_range), 1 + MATCH(N19, lookup_range, 1)))
N19 is the cell holding the value you look up, lookup_range is the name of your lookup range, the condition refers to the first cell in the named range.
So all in all you can just do (adapt the formulas if you don't like named ranges):
# For the lower limit
=INDEX(lookup_range, IF(N19 < INDEX(lookup_range, 1), 1, MATCH(N19, lookup_range, 1)))
# For the higher limit
=INDEX(lookup_range, IF(N19 < INDEX(lookup_range, 1), 1, MIN(ROWS(lookup_range), 1 + MATCH(N19, lookup_range, 1))))
NOTA: You can also change the first argument of INDEX in these two formulas if you're interested in any other output range.
You could also try these two formulas:
=LOOKUP(1,0/FREQUENCY(-B1,-A1:A6),+A1:A6)
=LOOKUP(1,0/FREQUENCY(B1,A1:A6),+A1:A6)
Notes:
the list A1:A6 does not need to be sorted
if B1 is equal to one of the values in A1:A6 then both formulas return B1.
if B1 lies outside the range of values in A1:A6then one of the formulas returns #N/A
Use XMATCH, as explained on this site:
https://exceljet.net/formula/xmatch-reverse-search
XMATCH allows you to set the search direction, as follows:
=XMATCH(B1,A1:A6,0,-1)
Where B1 is the cell to match, A1:A6 is the array you are searching through, 0 indicates "exact match", and -1 selects searching in the reverse direction (starting with cell A6 and ending with A1).

Resources