How do I use FIND to manipulate cell text - excel

This is crazy.
I have =FIND("Model=",A3)+6 which produces 36.
I have =FIND("|",A3,FIND("Model=",A3)+6) which produces 40.
What does it take to get the results of 4?
=FIND("|",A3,FIND("Model=",A3)+6)-FIND("Model=",A3)+6 produces 16.
I am using Office 2007 with all current updates.
Logic says 40-36 should equal 4, but that is not what excel is producing.
This is my test string in A3
Year=1999|Make=Mercedes-Benz|Model=C230|Trim=Kompressor Sport Sedan 4-Door|Engine=2.3L 2295CC l4 GAS DOHC Supercharged
The formula that I am aiming for looks kinda like this:
=MID(A3,FIND("Model=",A3)+6,FIND("|",A3,FIND("Model=",A3)+6)-FIND("Model=",A3)+6)
This should return the results of C230 from above text.

You need to parenthesize in the '+6' before subtraction takes place, so change:
=FIND("|",A3,FIND("Model=",A3)+6)-FIND("Model=",A3)+6
to:
=FIND("|",A3,FIND("Model=",A3)+6)-(FIND("Model=",A3)+6)
so it subtracts the entire sum, not just the first part of the sum.
It's clearer looking at a trivial example - you wanted something like:
3 - (1 + 2) = 0
but instead were doing:
3 - 1 + 2 = 4

Related

How to fix the #SPILL! Error by displaying only the second value?

I have a column with some info displayed like that:
Product Info
I am the 3rd product from 2020
I was created in 1995 and I went public in 2021
I am a not sure if I'm from 2019 2020 2021
I have a formula to extract the year in the above column that is:
=IFERROR(FILTERXML("<k><m>"&SUBSTITUTE([#[Product Name]]," ","</m><m>")&"</m></k>","//m[.=number() and string-length()=4]"),"")
The problem with this formula is that it works fine with the first case, but it gives me a #SPILL! Error on the other two cases. My ideal output would be:
Product Info
Year
I am the 3rd product from 2020
2020
I was created in 1995 and I went public in 2021
2021
I am a not sure if I'm from 2019 2020 2021
Basically, for the first case, just return the 4 digits. EVERY time that I only have one sequence of 4 digits, I want to return that sequence.
For the second case, I want to return ONLY the second year. EVERY time I have 2 sequences of 4 digits, I want to return ONLY the second year.
For the third case, I want to return nothing. EVERY time I have more than 2 sequences of 4 digits, I want to return blank.
The last thing I tried to add was position()>5 and that would cut off the 1995 in the second example, but I would continue having the Error on the third example. Also, my list is quite huge, and I am not sure if the position()>5 thing would work for ALL products that fall in the same second example.
I am not very good with XPATH, so any help would be greatly appreciated.
Thank you!
Disclaimer: Below solution is written on the assumption that when 'count of years < 3', return the last given year. If 'count >= 3' then only return the last year if years come in pairs of two. Hence the use of 'modulus 2 == 0'.‡
You can expand the xpath for sure if you so desire. However, I'd rewrite it a little bit. Each predicate, the structure between the opening and closing square brackets, is a filter of a given nodelist. To write multiple of these structures is in fact anding such predicates. To get a better understanding of what most common xpath 1.0 functions can do within FILTERXML(), I'd like to redirect you to this post.
So to write a consecutive pattern of predicates I'd opt for:
[.*0=0] - First return a filtered nodelist of all numbers where a node multiplied by zero equals zero;
[string-length()=4] - Then return only those that are 4 characters long‡‡;
[position() = last() and (position() = 1 or position() mod 2 = 0)] - The 3rd and last predicate is the trickiest for your query. This is done with a first check that position() = last() meaning the node needs to be the last node in the filtered nodelist of step 2 and (position() = 1 or position() mod 2 = 0) means we want to check that this node is also at the 1st index or the modulus 2 of the indexed position equals 0‡‡‡.
Formula in B2:
=IFERROR(FILTERXML("<t><s>"&SUBSTITUTE(A2," ","</s><s>")&"</s></t>","//s[.*0=0][string-length()=4][position() = last() and (position() = 1 or position() mod 2 = 0)]"),"")
Whilst the above would work for Excel 2013 and higher‡‡‡‡, you do talk about spilled behaviour. If you happen to work with the current channel in ms365 you could also try:
=LET(x,TEXTSPLIT(A2," "),y,--FILTER(x,ISNUMBER(-(x&"**0"))*(LEN(x)=4),{1,2,3}),z,COUNT(y),IF(OR(z=1,MOD(z,2)=0),TAKE(y,,-1),""))
‡ If you need to simply return the last year if 'count < 3' then you can use xpath "//s[.*0=0][string-length()=4][position()<3 and position() = last()]" or ms365 formula =LET(x,TEXTSPLIT(A2," "),y,FILTER(x,ISNUMBER(-(x&"**0"))*(LEN(x)=4),""),IF(COUNTA(y)>2,"",TAKE(y,,-1))).
‡‡ Note that you can be more strict about this if you'd wish to validate that a year is between say 1900-2050 or so. One could replace the 1st and 2nd predicate with [.*1>1899][.*1<2051].
‡‡‡ Note that the order or writing your and/or statements in xpath do matter. We need to use explicit parentheses to control the precedence. See this
‡‡‡‡ This is not true for Excel Online or Excel for Mac
Just add a simple clause to determine the number of returns, for example using ROWS (since by default FILTERXML returns a vertical array):
=LET(
ζ, FILTERXML(
"<k><m>" &
SUBSTITUTE(
[#[Product Name]],
" ",
"</m><m>"
) & "</m></k>",
"//m[.=number() and string-length()=4]"
),
ξ, ROWS(ζ),
IF(ξ > 2, "", INDEX(ζ, ξ))
)
Edit: I might prefer to avoid FILTERXML here:
=LET(
ζ, TEXTSPLIT([#[Product Name]], " "),
ξ, -(ζ & "**0"),
IF(COUNT(ξ) > 2, "", IFERROR(-LOOKUP(1, FILTER(ξ, LEN(ζ) = 4)), ""))
)
You can try the following using TEXTAFTER function. Assuming you have years at the end delimited by space. If that is not the case, the formula can be adapted to have additional checks (it is a number and four-digit, but strictly speaking a year can have less or more than 4 digits). Let me know if the previous assumption doesn't apply so I can try to adapt it. The following is an array version, so you can use the entire table column in case you are using excel tables:
=LET(in,A2:A4,last,TEXTAFTER(in," ",-1),
IF(ISNUMBER(1*TEXTAFTER(SUBSTITUTE(in," "&last,"")," ",-1)),"",last))
For the case of more than one year, it removes the last year found, and if the second search is a number, then it returns empty, otherwise returns the previous year found.

EXCEL Look up max number (possible multiple results) and return another column same row

A B
1 Pilot1
3 Pilot2
4 Pilot3
6 Pilot4
15 Pilot5
10 Pilot6
3 Pilot7
8 Pilot8
15 Pilot9
What is the excel formula for looking up the highest value(s) in column A and returning the Pilot(s) name(s).
I am using right now:
=MAX(A1:A9) to return the max number cuz I need that info too.
And
=VLOOKUP(MAX(A1:A9), A1:B9, 2, FALSE)
and this give me the answer if there is on max or the first it comes to for multiple maxes.
So I would get with this:
15
Pilot5
It does not give me
15
15
Pilot5
Pilot9
I want the results to show:
15 - for the max # of flights done
Pilot5
Pilot9 - for the names of the pilots that have the max flight count
So I noted above a more elegant way to do this in Google Sheets. And there are some very obscure ways out there, but here is something simple. The downside is it does show some extra information. Let us say your data is in A1:B9 and in A10 you have =MAX(A1:A9) [this is not strictly needed, but like you said, you want it anyway -- and it makes the formula a little less ugly]
Then in C1 put the formula =if(A1=A$10,B1,"") which will be blank if the pilot is not the max and have the pilot name otherwise. Drag that formula down through C9. Now in C10 (or wherever) put =TEXTJOIN(", ",true,C1:C9)
which will put together your pilot(s) separated by comma and space, and with blank entries omitted.

IF Formula not calculating properly

I've structured a formula that should spit out a numerical answer that is basically a simple sum formula with IF statements assigning numerical values to qualitative inputs. Apologies for the length, I am looking at a number of different factors.Formula is:
Cell F36 contains:
=IF(F32="Medium-High", 18, IF(F32="High", 24, SUM(F16, IF(F20="High",5,IF(F20="Medium-High",4,IF(F20="Medium",3,IF(F20="Low-medium",2,IF(F20="Low",1))))),IF(F24="High",5,IF(F24="Medium-High",4,IF(F24="Medium",3,IF(F24="Low-Medium",2,IF(F24="Low",1))))),IF(F28="High",5,IF(F28="Medium-High",4,IF(F28="Medium",3,IF(F28="Low-Medium",2,IF(F28="Low",1,IF(F28="N/A",0)))))),IF(F30="N/A",0,IF(F30="High",5,IF(F30="Medium-High",4,IF(F30="Medium",3,IF(F30="Low-Medium",2,IF(F30="Low",1)))))),IF(F32="High",5,IF(F32="Medium-High",4,IF(F32="Medium",3,IF(F32="Low-Medium",2,IF(F32="Low",1,IF(F32="N/A",0)))))))))
F16 - contains values from 1 to 5
F20, F24, F28, F30, F32 - Are dropdowns, where you choose a value: Low, Low-Medium, Medium, Medium-High, High;
Right now, based on a test input, where: F16 = 5, F20 = Low (1), F24= Medium-High (4), F28 = N/A (0), F30 = Medium (3), F32 = Medium (3) my output in F36 is 11, however doing simple adding, I should be at 5+1+4+0+3+3 = 16.
Where am I losing 5 points?
You can create a table allocating numerical output to each qualitative inputs and using vlookup to get your output. For example, for a table created on K19:L25, the following can be used:
=SUM(F16,VLOOKUP(F20,K19:L25,2,FALSE),VLOOKUP(F24,K19:L25,2,FALSE),VLOOKUP(F28,K19:L25,2,FALSE),VLOOKUP(F30,K19:L25,2,FALSE),VLOOKUP(F32,K19:L25,2,FALSE))
EDIT:
Tried your formula and it gives the correct result. Maybe your 5 in F16 is not a numerical value? You can test it by using
=ISNUMBER(F16)
and it should give a TRUE if it is a number.
Debug embedded IFs is just hell.
What you are doing is recode a 5 levels scale. You may use alternative solutions.
a. place the 5 text values (from "Low" to "High") somewhere in a sheet, say in T1:T5, even better, give this range a name
then you can retrieve the values you search with
MATCH(F20,$T$1:$T$5,0)
b. if it's suitable for your use, you may use combo boxes, presenting the 5 choices and giving the desired answer (from 1 to 5) in a linked cell.
(maybe not the answer, but I can't comment…)
(This should be a comment but I needed the formatting capabilities of an answer)
This is the current logic of your formula:
Check cell F32: "Medium-High" outputs 18, "High" outputs 24
If F32 is neither of those, then SUM the following:
F16
Lookup for F20, F24, F28, F30, and F32 where the lookup for each is:
"High" = 5
"Medium-High" = 4
"Medium" = 3
"Low-Medium" = 2
"Low" = 1
I find it strange that you first check cell F32 only to check it again later in the sum. Because this current logic produces incorrect results, we can't really advise how to fix it without sample data and expected results. My guess is you are summing too many lookups by including the F32 in there, but that's just speculation without data.

How do I sum data based on a PART of the headers name?

Say I have columns
/670 - White | /650 - black | /680 - Red | /800 - Whitest
These have data in their rows. Basically, I want to SUM their values together if their headers contain my desired string.
For modularity's sake, I wanted to merely specify to sum /670, /650, and /680 without having to mention the rest of the header text.
So, something like =SUMIF(a1:c1; "/NUM & /NUM & /NUM"; a2:c2)
That doesn't work, and honestly I don't know what i should be looking for.
Additional stuff:
I'm trying to think of the answer myself, is it possible to mention the header text as condition for ifs? Like: if A2="/650 - Black" then proceed to sum the next header. Is this possible?
Possibility it would not involve VBA, a draggable formula would be preferable!
At this point, I may as well request a version which handles the complete header name rather than just a part of it as I believe it to be difficult for formula code alone.
Thanks for having a look!
Let me know if I need to elaborate.
EDIT: In regards to data samples, any positive number will do actually, damn shame stack overflow doesn't support table markdown. Anyway, for example then..:
+-------------+-------------+-------------+-------------+-------------+
| A | B | C | D | E |
+---+-------------+-------------+-------------+-------------+-------------+
| 1 |/650 - Black |/670 - White |/800 - White |/680 - Red |/650 - Black |
+---+-------------+-------------+-------------+-------------+-------------+
| 2 | 250 | 400 | 100 | 300 | 125 |
+---+-------------+-------------+-------------+-------------+-------------+
I should have clarified:
The number range for these headers would go from /100 - /9999 and no more than that.
EDIT:
Progress so far:
https://docs.google.com/spreadsheets/d/1GiJKFcPWzG5bDsNt93eG7WS_M5uuVk9cvkt2VGSbpxY/edit?usp=sharing
Formula:
=SUMPRODUCT((A2:D2*
(MID($A$1:$D$1,2,4)=IF(LEN($H$1)=4,$H$1&"",$H$1&" ")))+(A2:D2*
(MID($A$1:$D$1,2,4)=IF(LEN($I$1)=4,$I$1&"",$I$1&" ")))+(A2:D2*
(MID($A$1:$D$1,2,4)=IF(LEN($J$1)=4,$J$1&"",$J$1&" "))))
Apparently, each MID function is returning false with each F9 calculation.
EDIT EDIT:
Okay! I found my issue, it's the /being read when you ALSO mentioned that it wasn't required. Man, I should stop skimming!
Final Edit:
=SUMPRODUCT((RETURNSUM*
(MID(HEADER,2,4)=IF(LEN(Match5)=4,Match5&"",Match5&" ")))+(RETURNSUM*
(MID(HEADER,2,4)=IF(LEN(Match6)=4,Match6&"",Match6&" ")))+(RETURNSUM*
(MID(HEADER,2,4)=IF(LEN(Match7)=4,Match7&"",Match7&" ")))
The idea is that Header and RETURNSUM will become match criteria like the matches written above, that way it would be easier to punch new criterion into the search table. As of the moment, it doesn't support multiple rows/dragging.
I have knocked up a couple of formulas that will achieve what you are looking for. For ease I have made the search input require the number only as pressing / does not automatically type into the formula bar. I apologise for the length of the answer, I got a little carried away with the explanation.
I have set this up for 3 criteria located in J1, K1 and L1.
Here is the output I achieved:
Formula 1 - SUMPRODUCT():
=SUMPRODUCT((A4:G4*(MID($A$1:$G$1,2,4)=IF(LEN($J$1)=4,$J$1&"",$J$1&" ")))+(A4:G4*(MID($A$1:$G$1,2,4)=IF(LEN($K$1)=4,$K$1&"",$K$1&" ")))+(A4:G4*(MID($A$1:$G$1,2,4)=IF(LEN($L$1)=4,$L$1&"",$L$1&" "))))
Sumproduct(array1,[array2]) behaves as an array formula without needed to be entered as one. Array formulas break down ranges and calculate them cell by cell (in this example we are using single rows so the formula will assess columns seperately).
(A4:G4*(MID($A$1:$G$1,2,4)=IF(LEN($J$1)=4,$J$1&"",$J$1&" ")))
Essentially I have broken the Sumproduct() formula into 3 identical parts - 1 for each search condition. (A4:G4*: Now, as the formula behaves like an array, we will multiply each individual cell by either 1 or 0 and add the results together.
1 is produced when the next part of the formula is true and 0 for when it is false (default numeric values for TRUE/FALSE).
(MID($A$1:$G$1,2,4)=IF(LEN($J$1)=4,$J$1&"",$J$1&" "))
MID(text,start_num,num_chars) is being used here to assess the 4 digits after the "/" and see whether they match with the number in the 3 cells that we are searching from (in this case the first one: J1). Again, as SUMPRODUCT() works very much like an array formula, each cell in the range will be assessed individually.
I have then used the IF(logical_test,[value_if_true],[value_if_false]) to check the length of the number that I am searching. As we are searching for a 4 digit text string, if the number is 4 digits then add nothing ("") to force it to a text string and if it is not (as it will have to be 3 digits) add 1 space to the end (" ") again forcing it to become a text string.
The formula will then perform the calculation like so:
The MID() formula produces the array: {"650 ","670 ","800 ","680 ","977 ","9999","143 "}. This combined with the first search produces {TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE} which when multiplied by A4:G4
(remember 0 for false and 1 for true) produces this array: {250,0,0,0,0,0,0} essentially pulling the desired result ready to be summed together.
Formula 2: =SUM(IF(Array)): [This formula does not work for 3 digit numbers as they will exist within the 4 digit numbers! I have included it for educational purposes only]
=SUM(IF(ISNUMBER(SEARCH($J$1,$A$1:$G$1)),A8:G8),IF(ISNUMBER(SEARCH($K$1,$A$1:$G$1)),A8:G8),IF(ISNUMBER(SEARCH($L$1,$A$1:$G$1)),A8:G8))
The formula will need to be entered as an array (once copy and pasted while still in the formula bar hit CTRL+SHIFT+ENTER)
This formula works in a similar way, SUM() will add together the array values produced where IF(ISNUMBER(SEARCH() columns match the result column.
SEARCH() will return a number when it finds the exact characters in a cell which represents it's position in number of characters. By using ISNUMBER() I am avoiding having to do the whole MID() and IF(LEN()=4,""," ") I used in the previous formula as TRUE/FALSE will be produced when a match is found regardless of it's position or cell formatting.
As previously mentioned, this poses a problem as 999 can be found within 9999 etc.
The resulting array for the first part is: {250,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE} (if you would like to see the array you can highlight that part of the formula and calculate with F9 but be sure to highlight the exact brackets for that part of the formula).
I hope I have explained this well, feel free to ask any questions about stuff that you don't understand. It is good to see people keen to learn and not just fishing for a fast answer. I would be more than happy to help and explain in more depth.
I start this solution with the names in an array, you can read the header names into an array with not too much difficulty.
Sub test()
Dim myArray(1 To 4) As String
myArray(1) = "/670 - White"
myArray(2) = "/650 - black"
myArray(3) = "/680 - Red"
myArray(4) = "/800 - Whitest"
For Each ArrayValue In myArray
'Find position of last character
endposition = InStr(1, ArrayValue, " - ", vbTextCompare)
'Grab the number section from the string, based on starting and ending positions
stringvalue = Mid(ArrayValue, 2, endposition - 2)
'Convert to number
NumberValue = CLng(stringvalue)
'Add to total
Total = Total + NumberValue
Next ArrayValue
'Print total
Debug.Print Total
End Sub
This will print the answer to the debug window.

Excel IF function help wanted

I can't upload the picture don't have enough points but this is the link Pic
I used this formula
=IF(E43>12,"1","0.5")
The thing is I'm trying to make this IF function work...
I'd like it to do this
if in E43 says 0.1-11.59 to write in F43 0.5,
if in E43 says 12-23.59 to write in F43 1,
if in E43 says 24-47.59 to write in F43 2... etc.
In E43 is hours I got everything else sorted but this is a problem...
This is probably the most straight forward answer, but it can get tedious to type out. Don't forget to set it greater or EQUAL to or less than or EQUAL to or your statement will fail at the low and high ranges. Set F43 equal to this... =IF(AND(11.59>=E43,E43>=0.1),0.5,IF(AND(23.59>=E43,E43>=12),1,IF(AND(47.59>=E43,E43>=L24),2,"Greater than 47")))
There are a few ways you can do this. If the value in F43 is uniformly based on E43, you could use a formula like
=CEILING(E43/23.999,0.5)
But if the value in F43 isn't uniform (like your example of 24-47.59 = 2) then you can either:
1)
Write a long nested if statement with several AND() functions (i.e. AND(E43>=24,E43<=47.59), or
2)
write a table of vlookup values i.e.
0 | 0.5
12 | 1
24 | 2
and the formula
=VLOOKUP(C7,$C$12:$D$14,2,TRUE)

Resources