Excel: order effects in arrays - excel

I'm currently using this expression to check if a cell contains at least one of a set of strings:
A B
1 abcd =ISNUMBER(SEARCH({"a","x"},A1))
B1 will return true here. However if I change the order of the array as follows it returns false:
A B
1 abcd =ISNUMBER(SEARCH({"x","a"},A1))
Why is that? Is there a better way to do this that's more elegant than using a bunch of OR()'s?

Say we have text in A1 and we also have a list of sub-strings in column C. These can be either single or multiple character substrings. We assign the Name - KeyStrings to the list of cells in column C
We want to know if any of the substrings is present in A1.
Enter the following in B1:
=NOT(LEN(TRIM(SUBSTITUTE(A1,INDEX(KeyStrings,SUMPRODUCT(ROW(KeyStrings)*ISNUMBER(SEARCH(KeyStrings,A1)))),"")))=LEN(A1))
The formula will report True if any of the substrings in column C can be found in A1

Just for completeness, the answer to the original question "Why is that?" i.e. why does the result seem to be sensitive to the order of the strings in curly brackets is that the formula
=ISNUMBER(SEARCH({"a","x"},A1))
only looks at at the first string "a" because there is nothing to make it operate like an array formula and step through all the values "a","x" etc.
The usual procedure is to wrap the function in an aggregate function like SUM. If you do this you also have to add minus signs to make the TRUE/FALSE values from ISNUMBER behave as ones and zeroes and further wrap in SUMPRODUCT or enter it as an array formula to make it work:-
=SUMPRODUCT(SUM(--ISNUMBER(SEARCH({"a","x"},A1))))
Even then it gives a numeric result which is not what you actually want.
# Dirk Reichel's idea is therefore much better giving you:-
=OR(ISNUMBER(SEARCH({"a","x"},A1)))
which works very nicely and incidentally doesn't need to be entered as an array formula.

I think since you have put a curly bracket there, it indicates an array search. (I am not an expert with arrays, so following is an educated guess).
What Excel is doing is in the first example, it is finding "a" in position no 1, so it is returning the no 1 to ISNUMBER function, which is TRUE. (Basically, compares "a" to a in abcd which is position 1, and doesn't find/look for[?] "x". Returns 1 for the "a", which is TRUE for ISNUMBER function)
In the 2nd code, "x" is compared to a from abcd, which returns a non-numeric value (and doesn't find/look for[?] "a"), hence it is FALSE.
PS:
what I mean by Excel doesn't find/look for[?] the second or any element there on, seems to be based on how arrays and formulae are coded in. In the curly brackets, commas separate "columns" and semi-colons separate "rows". So you are entering a 2 column/1row array inside a search function. While there is nothing wrong with that, the SEARCH function itself may not be coded to look for any element in the array apart from the one in position [1,1]. Someone better informed with the inner workings of SEARCH function should confirm this answer. (If it is a completely wrong educated guess, I wouldn't mind taking it off)

Related

Excel search function with a list of things - array behaves weird?

I have a list of substrings and need to check if the text string in my cell contains any of these substrings. Exactly like here: https://exceljet.net/formula/cell-contains-one-of-many-things
However, the ISNUMBER(SEARCH(MySubstrings,A3)) behaves strangely. Instead of checking A3 against a list of substrings like ISNUMBER(SEARCH({dog, cat, egg},A3)) it automatically populates three subsequent cells to show results for checking A3 against every item on my list, one by one.
search without curly brackets
And when I enter the same thing as an array formula, it only checks for occurrence of the first substring from my list, in this case "dog".
search with curly brackets
Why does this not work? Thanks for your hints!
You're missing the SUMPRODUCT function as in the exceljet example. The argument passed to SUMPRODUCT is an array (in your example, a 1-by-3 array of TRUE or FALSE), which SUMPRODUCT turns into a single value (0 or 1):
=SUMPRODUCT(--ISNUMBER(SEARCH({"dog","cat","egg"},A3)))>0
An alternative formulation would be to wrap ISNUMBER with the OR function (still no need to enter as an array):
=OR(ISNUMBER(SEARCH({"dog","cat","egg"},A3)))

Excel sumifs with two values throwing an error

I am trying to get a sum of column C if A is abc or cba and B is def:
=SUMIFS(C2:C51;A2:A51;{"abc","cba"};B2:B51;"def")
But the formula is not valid, not sure where is my mistake since this was proposed in a quick google search.
Thank you for your suggestions.
The formula is valid for me, but this might be an issue with your delimiter. Depending on your excel, windows or location settings you might need to use a comma , as a delimiter, instead of a semicolon ;.
As for your formula, for completion I've done the same google search and ended up with this reference. It seems your logic in the formula is correct apart from one crucial step, the SUM( wrapping around your formula. This means if your formula works, it will only take the first hit into account, but with the sum, it will count every entry where your logic is True. Syntax:
=SUM(SUMIFS(C2:C51,A2:A51,{"abc","cba"},B2:B51,"def"))
Or semicolon delimited:
=SUM(SUMIFS(C2:C51;A2:A51;{"abc";"cba"};B2:B51;"def"))
Since the {array} option does not seem to be working for you, I propose a workaround as follows:
=SUMIFS(C1:C15;A1:A15;"abc";B1:B15;"def")+SUMIFS(C1:C15;A1:A15;"cba";B1:B15;"def")
This is a more clunky function, but reaches the same result by splitting up the data in two SUMIFS( functions and adding the results together.
Probably I would use #Plutian answer (actually I upvoted), but in case it might work for you, you can use SUMPRODUCT combined with DOUBLE UNARY to get exactly what you want.
DOUBLE UNARY
SUMPRODUCT
I made a fake dataset like this:
As you can see, only the highlighted values meet your requirements ( if A=abc OR cba AND B=def)
My formula in E10 is:
=SUMPRODUCT(--($A$2:$A$7="abc")+--($A$2:$A$7="cba");--($B$2:$B$7="def");$C$2:$C$7)
This is how it works:
($A$2:$A$7="abc") will return an array of True/False values if condition is met.
That array, because it's inside a double unary operator --( your range ), will convert all True/False values into 1 or 0 values. Let's say it works like if you would have selected a range of cells that contains only 1 or 0. So this will return an array like {1,0,1,0,1,0} in this case
--($A$2:$A$7="cba") will do exactly the same than steps 1 or 2 again, but with your second option. It will return another array of values, in this case, {0,1,0,1,0,1}
--($A$2:$A$7="abc")+--($A$2:$A$7="cba") we are just summing up both arrays, so {1,0,1,0,1,0}+{0,1,0,1,0,1}={1,1,1,1,1,1}
--($B$2:$B$7="def") will do like steps 1 and 2 again with your third condition, and will return another array, now it will be {1,0,1,0,0,1}
The array obtained in step 5 then it's multiplied to array obtained in step 4, so we are doing {1,1,1,1,1,1} * {1,0,1,0,0,1}={1,0,1,0,0,1}
Now, that final array obtained in step 7 then it's multiplied by the values of cells $C$2:$C$7, so in this case is {1,0,1,0,0,1} * {10,1,10,1,1,10} = {10,0,10,0,0,10}
And final step, we sum up all values inside array obtained in last step, so we do 10+0+10+0+0+10=30
I've explained every step to make sure everybody can understand, because SUMPRODUCT it's really an useful function if you know how to hanlde (I'm a noob, but I've seen real heroes here on SO using this function).
The advantage of using SUMPRODUCT instead of SUMIFS is that you can easily add more conditions to apply same range (case --($A$2:$A$7="abc")+--($A$2:$A$7="cba") or single condition to additional ranges (case --($B$2:$B$7="def")).
With normal SUMIFS probably you would have to add 1 extra complete SUMIF for each condition applied in same range.
Hope this helps

Index Inside If with Array

I am trying to figure out how to reference just one area of a named formula and return it as an array. This is so I can then count the number of rows in the areas referenced and eventually sum them. I going to eventually integrate the results of this into a pretty complicated mess of other formulas that automatically join and rank multiple matrices. I am trying to do this using formulas, not VBA, as a portability requirement. Some folks are a bit weary about running other folks code...
For now, though, I've come up with a simple example. Let's pretend that in the name manager we have a formula named Letters that is defined as:
=A1:A4,C1:C6
The range A1:A4 contains the letters "A" through ."D" and the range C1:C6 contains the letters "E" through "J".
If I write a simple INDEX formula I can return the first or second area of Letters like so:
=INDEX(Letters,,,1)
=INDEX(Letters,,,2)
I know this works by doing an F9 in on the formula and it returns the expected array of letters ({"A";"B";"C";"D"} or {"E";"F";"G";"H";"I";"J"}) for the appropriate area. But doing it this way makes the assumption that there will always be two areas in Letters. I'd like to keep my formula dynamic in case I was to add another area. I can create another formula named Letters_Areas and make it equal to the following:
=ROW(INDEX(Sheet1!$A:$A,1):INDEX(Sheet1!$A:$A,AREAS(Letters)))
This will return an array with the value of {1;2} for the example (or more if there was more areas) and I can pass that to an IF to loop like so:
=IF(Letters_Areas,INDEX(Letters,,,Letters_Areas)
But that doesn't work. It always returns just the first area in Letters because Letters_Areas in the second argument of the IF always returns 1 as the value, not the first and then second value of the array. I guess my question in a formula is:
=IF(Letters_Areas,INDEX(Letters,,,What_Do_I_Put_Here))
Where What_Do_I_Put_Here counts up for each iteration of the IF like a For loop would in VBA. Essentially, I need to be able to get i in my For i = 1 to 2 in this case inside the IF.
I know that the failure is the Letters_Areas in the second argument of the IF because I can test it. At first glance you would just do it as such:
=IF(Letters_Areas,Letters_Areas)
This returns the expected {1,2}. However, this is misleading because you can find the true behavior by doing this:
=IF(Letters_Areas,INDEX(Letters_Areas,Letters_Areas))
And this always returns {1,1} which tells me that is the part that is failing.
The final version of the formula, minus the part I cannot figure out should look something like:
=IF(Letters_Areas,ROWS(INDEX(Letters,,,What_Do_I_Put_Here)))
And in our test example this would return {4;6}. Again, stuck using no VBA. Any ideas?
Could you use this formula to count areas, assuming that your areas always begin in row 1 as in your example: COLUMNS(A1:Z1)-(SUM(IF(ISBLANK(A1:Z1),1,0)))? Any non-blank cells within that range will be counted as an area and will give the correct count. I am not sure if this is what you are seeking according to your question.

Multiple if search statements in excel?

I am trying to convert text of the month to the number
B2 cell:
BirthMonth_Jan
BirthMonth_Feb
BirthMonth_mar
BirthMonth_Apr
BirthMonth_May
BirthMonth_Jun, ect to december
for example, BirthMonth_Jan will output 1 based on the search of Jan, so i can compare this to another set of numbers
I have this, and tried this, but only works with two if statements, is there anyway i can do this with 12?
=(IF(ISNUMBER(SEARCH("sep",B2)),"9")),(IF(ISNUMBER(SEARCH("aug",B2)),"8")),(IF(ISNUMBER(SEARCH("jul",B2)),"7")),(IF(ISNUMBER(SEARCH("jun",B2)),"6")),(IF(ISNUMBER(SEARCH("may",B2)),"5")),(IF(ISNUMBER(SEARCH("apr",B2)),"4")),(IF(ISNUMBER(SEARCH("mar",B2)),"3")),(IF(ISNUMBER(SEARCH("feb",B2)),"2")),(IF(ISNUMBER(SEARCH("jan",B2)),"1"))
I get #Value!
If i try this, it also doesn't work
=IF(ISNUMBER(SEARCH("dec",B2)),"12",IF(ISNUMBER(SEARCH("nov",B2)),"11")),IF(ISNUMBER(SEARCH("DSH_KnowBe4_BirthMonth_Oc",B2)),"10"))
the second option only works with two but if i add more it throws an error
The questioner is trying to obtain a numeral equivalent to a partial month name extracted from a string. There are any number of examples in stackoverflow and the net generally on this theme. What is special in this case is the partial month name in the target cell, and use of the IF statement. The questioner is right to use search since it is not case-sensitive
Two formula are offered:
Formula 1
=(IF(ISNUMBER(SEARCH("sep",B2)),"9")),(IF(ISNUMBER(SEARCH("aug",B2)),"8")),(IF(ISNUMBER(SEARCH("jul",B2)),"7")),(IF(ISNUMBER(SEARCH("jun",B2)),"6")),(IF(ISNUMBER(SEARCH("may",B2)),"5")),(IF(ISNUMBER(SEARCH("apr",B2)),"4")),(IF(ISNUMBER(SEARCH("mar",B2)),"3")),(IF(ISNUMBER(SEARCH("feb",B2)),"2")),(IF(ISNUMBER(SEARCH("jan",B2)),"1"))
The questioner said "I get #Value!"
This is not a surprise because it is essentially a series of nine, self-contained, unrelated if statements, each separated by a comma. It is an invalid statement.
However, if the if statements were nested, then the formula would work. Something along these lines:
=IF(ISNUMBER(SEARCH("jan",B2)),"1",IF(ISNUMBER(SEARCH("feb",B2)),"2",IF(ISNUMBER(SEARCH("mar",B2)),"3")))
Formula 2
=IF(ISNUMBER(SEARCH("dec",B2)),"12",IF(ISNUMBER(SEARCH("nov",B2)),"11")),IF(ISNUMBER(SEARCH("DSH_KnowBe4_BirthMonth_Oc",B2)),"10"))
So close and yet so far... This statement uses the nested approach mentioned above. There is a major typo for the October search (instead of searching for "oct", the formula searches for "DSH_KnowBe4_BirthMonth_Oc") though this doesn't cause the formula to fail.
Failure is caused by two things:
1) The double bracket following "11")) in the "November" search. There should be zero brackets here.
2) The formula needs an additional closing bracket.
Two other things to note:
1) in the event of a match, the value returned is a string not an integer.
2) there's no provision to return a value in the event of a failure to match.
Working IF statement formula
The following formula, consisting of nested IF statements, works as intended by the questioner.
=IF(ISNUMBER(SEARCH("jan",B2)),"1",IF(ISNUMBER(SEARCH("feb",B2)),"2",IF(ISNUMBER(SEARCH("mar",B2)),"3",IF(ISNUMBER(SEARCH("apr",B2)),"4",IF(ISNUMBER(SEARCH("may",B2)),"5",IF(ISNUMBER(SEARCH("jun",B2)),"6",IF(ISNUMBER(SEARCH("jul",B2)),"7",IF(ISNUMBER(SEARCH("aug",B2)),"8",IF(ISNUMBER(SEARCH("sep",B2)),"9",IF(ISNUMBER(SEARCH("oct",B2)),"10",IF(ISNUMBER(SEARCH("nov",B2)),"11",IF(ISNUMBER(SEARCH("dec",B2)),"12",NA()))))))))))))
Note, the formula uses the NA() function to return #N/A if there is no match.
VLOOKUP alternative
Though the above-mentioned formula works, I find it complicated and inflexible. My preference in situations like this is VLOOKUP. My equivalent formula would be:
=VLOOKUP(RIGHT(B2,LEN(B2)-SEARCH("_",B2)),Sheet2!$A$2:$B$13,2,FALSE)
Using January as an example: BirthMonth_Jan, the formula lookup works like this:
RIGHT(B2,LEN(B2)-SEARCH("_",B2))
1) search for the underline character SEARCH("_",B2),
2) deduct the result from the total length LEN(B2)-SEARCH("_",B2) to give the number of characters to the right of the underline.
3) get all the characters to the right of the underline RIGHT(B2,LEN(B2)-SEARCH("_",B2)). This is the lookup value
4) Create a reference table on another sheet (refer screenshot); lookup this table and return column 2 (the number for that month).
5) If there is no valid result, VLOOKUP automatically returns #N/A.
The reference table on a separate sheet:
Not sure what you are trying to do with the formula but if your "BirthMonth_" text is consistent, you can use :
=MONTH(DATEVALUE("1 "&SUBSTITUTE(A12,"BirthMonth_","")&" 2018"))
Having a view of your data and expected result would help if this is not what you're after.
It is seems just possible what you might want is:
=MONTH(MID(B2,SEARCH("BirthMonth_",B2)+11,3)&0)
Returns a Number.

Assign an Excel function result to a variable within a cell

I'm working on an Excel spreadsheet where I'm using VLOOKUP to get data from another sheet. I have it working, but it's giving me an annoying "0" for blank results. I'd like to incorporate ISBLANK to address it.
My problem is the syntax. I REALLY do NOT want to retype the entire VLOOKUP function for the results if it returns FALSE.
In other words, what I'm trying to avoid doing is this:
=IF(ISNULL(VLOOKUP($A2,Sheet!$B$1:Sheet!$C$200,2)),"",VLOOKUP($A2,Sheet!$B$1:Sheet!$C$200,2))
Ideally, what I want to do is something like this:
=IF(ISNULL(VLOOKUP($A2,Sheet!$B$1:Sheet!$C$200,2)),"",[some variable that stores the result of the VLOOKUP])
Ideas, anyone? Thanks...
Are you open to formatting? You can hide the zeros that way, and therefore keep the formula short.
Highlight the range of the VLOOKUP() results, and go to Formatting, then Custom. Use this format and any 0 will be effectively hidden:
0;-0;;#
It depends whether you're looking up text or numbers.
If you want the result of your expression to be text that you're looking up, it's as simple as wrapping your VLOOKUP with the function T().
So, for text, replace VLOOKUP($A2,Sheet!$B$1:Sheet!$C$200,2,FALSE) with T(VLOOKUP($A2,Sheet!$B$1:Sheet!$C$200,2,FALSE))
If the result of your expression is a number, and your VLOOKUP expression is too complicated to repeat, then you can avoid writing it twice by sneakily using IFERROR. The trick is to make it so that when VLOOKUP returns 0, it makes an error, but otherwise it returns what VLOOKUP returned. And you can do this by taking advantage of some maths: Where x<>0, then 1/(1/x) = x. When x=0, Excel returns #DIV/0!. If we use IFERROR, then we can replace that with an empty string ("")
So, for numbers, replace VLOOKUP($A2,Sheet!$B$1:Sheet!$C$200,2,FALSE) with IFERROR(1/(1/VLOOKUP($A2,Sheet!$B$1:Sheet!$C$200,2,FALSE)),"")
By the looks of it the formula you're asking for is:
=IF(VLOOKUP($A2,Sheet!$B$1:$C$200,2,FALSE)="","",VLOOKUP($A2,Sheet!$B$1:$C$200,2,FALSE))
Edit: The FALSE at the end of the function is so it only finds an exact match. Omitting it, or setting it as True, returns an exact or the next largest value that is less than the lookup value - your list must be sorted in ascending order for that to work.
Note the range reference to the sheet called Sheetis Sheet!$B$1:$C$200 and not Sheet!$B$1:Sheet!$C$200.
Having said that, an easier way is just to hide the 0 returns with number formatting.
Give the cell a custom number format of:
#,##0;-#,##0;;#
The first section #,##0 is the format for positive numbers, the second -#,##0 for negative numbers, the third ;;(no format set) for zeros and the last # for text.

Resources