For an example, string A,B;C
I am doing this formula, =TEXTSPLIT(CHOOSECOLS(TEXTSPLIT("A,B;C",","),2),";")
TEXTSPLIT inside will give 2 element column array A and B;C
Then, CHOOSECOLS(*,2) over it will give B;C since it is the 2nd element in the array
It is ok till now. If I TEXTSPLIT over this with ; as a separator, then I expect again a 2-element column array B and C. Instead, I get only the first element as result, that is B. What is going wrong here? Is it a bug? I know if I do like TEXTSPLIT("A,B;C",{",",";"}), I will get my result, but I have a different sort of scenario. My actual text looks more like A,B,C;D,E,F, and I need D E F as array. If I do something like =TEXTSPLIT(CHOOSECOLS(TEXTSPLIT("A,B,C;D,E,F",";"),2),","), I get only D, instead of expected array
Another observation I had is that, if I spilt the operation into 2, say I put the result of CHOOSECOL in a cell, and do another TEXTSPLIT in another cell, I get the result. But I don't want to do it in another cell.
As I mentioned in my comment, simply replace CHOOSECOLS with INDEX:
=TEXTSPLIT(INDEX(TEXTSPLIT("A,B,C;D,E,F",";"),2),",")
For this case using the Implicit Intersection operator (#) solves your problem. Just add to your formula the #-operator before CHOOSECOLS:
=TEXTSPLIT(#CHOOSECOLS(TEXTSPLIT("A,B;C",","),2),";")
Output:
CHOOSECOLS returns 1x1 array and TEXTSPLIT as its name indicates, it operates at a text (string) level. The #-operator converts the array into a string. We would expect here that Excel would do the cast for us, but it doesn't happen.
You can check the above rationale by looking at the steps Excel carries out via Evaluate Formula functionality:
The intermediate result after CHOOSECOLS call`:
The intermediate result after #-Operator:
It is the same intermediate result as #JosWoolley's answer using INDEX.
Try-
=TEXTSPLIT(TEXTJOIN("",,CHOOSECOLS(TEXTSPLIT("A,B;C",","),2)),";")
CONCAT() may also work.
=TEXTSPLIT(CONCAT(CHOOSECOLS(TEXTSPLIT("A,B;C",","),2)),";")
Related
I'm trying to make my monthly transaction spreadsheet less work-intensive but I'm running up against problems outputting my category lookups as an array. Right now I have a table with all my monthly transactions and I want to create another table with monthly running totals. What I've been doing is manually summing each entry from each category, but I'd love to automate the process. Here's what I have:
=SUM(INDEX(Transactions[Out], N(IF(1,MATCH(I12,Transactions[Category],FALSE)))))
I've also tried using AGGREGATE in place of SUM but it still only returns the first value in the category. The N(IF()) was supposed to force INDEX to return all the matches as an array, but it's not working. I found that trick online, with no explanation of why it works, so I really don't know how to fix it. Any ideas?
Just in case anyone ever looks at this thread in the future, I was able to find a simpler solution to my problem once I implemented the Transactions[Category]=I12 method. SUM, itself will take an array as an argument, so all I had to do was form an array of the values I wanted to keep from Transactions[Out] range. I did this by adjusting the method Ron described above, but instead of using 1/(Transactions[Category]=I12 I used 1/IF(Transactions[Category]=I12, 1,1000) and surrounded that by a FLOOR(*resulting array*, .01) which rounded all the thousandth's down to zero and didn't yield any #DIV/0! errors.
Then! I realized that the simplest way to get the actual numbers I wanted, rather than messing with INDEX or AGGREGATE, was to multiply the range Transactions[Out] by the binary array from the IF test. Since the range is a table, I know they will always be the same size. And SUM automatically multiplies element by element and then adds for operations like this.
(The result is a "CSE" formula, which I guess isn't everyone's favorite. I'm still not 100% clear on what it means: just that it outputs data in a single cell, rather than over multiple cells. But in this context, SUM should only output a single number, so I'm not sure why I need CSE... A problem for another day!)
In your IF, the value_if_true clause needs to return an array of the desired row numbers from the array.
MATCH does not return an array of values; it only returns a single value which, with the FALSE parameter, will be the first value. That's why INDEX is only returning the first value.
One way to return an array of values:
Transactions[Category]=I12
will return an array of {TRUE,FALSE,FALSE,TRUE,...} depending on if it matches.
You can then multiply that by the Row number to get the relevant row on the worksheet.
Since you are using a table, to obtain the row number in the data body array, you have to subtract the row number of the Header row.
But now we are going to have an array which includes 0's for the non-matching entries, which is not good for us as a row number argument for the INDEX function.
So we get rid of that by using the AGGREGATE function with the ignore errors argument set after we do change the equality test to 1/(Transactions[Category]=I12) which will create DIV/0 errors for the non-matchers.
Putting it all together
=SUM(INDEX(Transactions[Out],AGGREGATE(15,6,1/(Transactions[Category]=I12)*ROW(Transactions)-ROW(Transactions[#Headers]),ROW(INDIRECT("1:"&COUNTIF(Transactions[Category],$I$12))))))
You may need to enter this with CSE depending on your version of Excel.
Also, if you have a lot of these formulas, you may want to change the k argument for AGGREGATE to use the INDEX function (non-volatile) instead of the volatile INDIRECT function.
=SUM(INDEX(Transactions[Out],AGGREGATE(15,6,1/(Transactions[Category]=I12)*ROW(Transactions)-ROW(Transactions[#Headers]),ROW(INDEX($A:$A,1,1):INDEX($A:$A,COUNTIF(Transactions[Category],$I$12),1)))))
Edit
If you have Excel/O365 with dynamic arrays and the FILTER function, you can greatly simplify the above to the normally entered:
=SUM(FILTER(Transactions[Out],Transactions[Category]=I12))
I need a function to look up organizational abbreviations in a text and return the first one thas shows up. I tried to solve that with a nested if clause but it has a logical error.
=IF(ISNUMBER(SEARCH("BZC";I5)); "Finanz"; IF(ISNUMBER(SEARCH("AZC" /1";I5));"IT";""))
It looks up BZC and AZC as desired and return the organization name. However, it does no return the first match in a string. Since BZC is the first lookup it will always be returned if it is in the string, eventhoug it might not be the first org abbreviation.
What functionality of excel can be used to solve this issue? I basically need an array of variables that a function should do a look up and return the first one that is found.
Edit:
I tried to implement the formula form Justyna MK. Besides the fact, that I still need to figure out the meaning of the formula (iferror, mid, small) It returns #N/A in my example. Is there a certain reason for that?
I hope I understood your request correctly. Here's an Array formula for you to try (enter using Ctrl + Shift + Enter):
=CHOOSE(MATCH(MID(A1,SMALL(IFERROR(SEARCH({"BZC","AZD","xxx"},A1),""),1),3),{"BZC","AZD","xxx"},0),"Finanz","IT","Other")
You'd probably need to change , to ; in order to match your regional settings.
You can easily expand the list of search items by modifying the contents of curly brackets { } and also by expanding the MATCH results at the very end of the formula.
Here's some sample result:
Edit: here's an adjusted solution that ignores the length of your code (the previous solution was assuming that the code is always 3-characters long). This time it's not an array formula so you can enter it as it is.
Also, I suspect that you should not change , to ; inside the curly brackets (it would modify the formula from column to row delimiter and thus it will stop working). The remaining , can be transformed to ;, if that makes sense.
=CHOOSE(MATCH(TRIM(LEFT(SUBSTITUTE(RIGHT(A1,LEN(A1)-SUMPRODUCT(SMALL(IFERROR(SEARCH({"BZC","AZD","XYZX/1","NP-HSD"},A1),""),1))+1)," ",REPT(" ",255)),255)),{"BZC","AZD","XYZX/1","NP-HSD"},0),"Finanz","IT","Other1","Other2")
The result:
I have been trying to get this function to work but cant seem to get the correct result. What I am trying to accomplish is to Index Match Match a cell from the second table to the first table and evaluate the first set of coordinates, lets say (a,c) , with another set of coordinates (c,a). I will always be evaluating the inverse of each others coordinate. If all goes correctly, the two points in this example are -4 and 4. If the two coordiantes match eachothers inverse then True, otherwise False. I think I set up my function correctly but I cant seem to find the issue with it.
=(INDEX($B$2:$F$6,MATCH($A14,$A$2:$A$6,0),MATCH(B$13,$B$1:$F$1,0)))=(-(INDEX($B$2:$F$6,MATCH($A14,$B$1:$F$1,0),MATCH(B$13,$A$2:$A$6,0))))
Try this formula:
=B2=-INDEX($B$2:$F$6,MATCH(B$1,$B$1:$F$1,0),MATCH($A2,$A$2:$A$6,0))
I think you just mixed up your rows and columns. Also, you don't need the first INDEX, you can just refer to the cell
Example (note I changed one value just to make sure it is working):
If it is always a square matrix, and you don't mind entering it as a single array formula, you could use TRANSPOSE. Enter this in a 5 x 5 area and commit with ctrl+shift+enter:
=-B2:F6=TRANSPOSE(B2:F6)
In an Excel array formula, I would like to test each element of one array against each element of a second array, when the 2 arrays do NOT have the same number of elements. Simplified right down, this scenario could be represented by:
=SUMPRODUCT({1,2,3,4,5}={1,2})
NB - in my real world scenario these arrays are calculated from various prior steps.
Using the above example, I would want a result of {TRUE,TRUE,FALSE,FALSE,FALSE}. What I get is {TRUE,TRUE,#N/A,#N/A,#N/A}.
It's clear that, when there's more than 1 value being tested for, Excel wants equal numbers of elements in the 2 arrays; when there isn't, the #N/A error fills in the blanks.
I've considered writing a UDF to achieve what I want, and I'm pretty sure my coding skills are up to creating something like:
=ArrayCompare({1,2,3,4,5},"=",{1,2})
But I'd much rather do this using native functionality if it's not too cumbersome...
So, simple question; can an array formula be constructed to do what I'm after?
Thanks peeps!
Using MATCH function is probably the best way.....but if you actually want to compare every element in one array with another array in a direct comparison then one should be a "column" and one a "row", e.g.
=SUMPRODUCT(({1,2,3,4,5}={1;4})+0)
Note the semi-colon separator in the second array
If you can't actually change the column/row designation then TRANSPOSE can be used, i.e.
=SUMPRODUCT(({1,2,3,4,5}=TRANSPOSE({1,4}))+0)
You may not get the required results if the arrays contain duplicates because then you will get some double-counting, e.g. with this formula
=SUMPRODUCT(({1,1,1,1,1}={1;1})+0)
the result is 10 because there are 5x2 comparisons and they are all TRUE
Maybe:
{=IF(ISERROR(MATCH({1,2,3,4,5},{1,2},0)),FALSE,TRUE)}
If the second array is a subset of the first array, same order, and starting at position 1 then you can use this array formula for equivalence testing:
=IFERROR(IF({1,2,3,4,5}={1,2},TRUE),FALSE)
For non equivalence just swap the FALSE and TRUE
=IFERROR(IF({1,2,3,4,5}={1,2},FALSE),TRUE)
You can then use this in other formulas just as an array:
However if the arrays are not in order, as in this example:
{1,2,3,4,5},{1,4,5}
Then you have to use MATCH. However all you need is to surround the match with an ISNUMBER like so:
Equivalence test:
=ISNUMBER(MATCH({1,2,3,4,5},{1,4,5},0))
Non Equivalence test:
=NOT(ISNUMBER(MATCH({1,2,3,4,5},{1,4,5},0)))
Remember all array formulas are entered with ctrl + shift + enter
(I understand Excel is only borderline programming)
I have a block of data that represents the steps in a process and the possible errors:
ProcessStep Status
FeesPaid OK
FormRecvd OK
RoleAssigned OK
CheckedIn Not Checked In.
ReadyToStart Not Ready for Start
I want to find the first Status that is not "OK".
I have attempted this:
=Match("<>""OK""", StatusRange, 0)
which is supposed to return the index of the first element in the range that is NOT-EQUAL (<>) to "OK"
But this doesn't work, instead returning #N/A.
I expect it to return 4 (index #4, in a 1-based index, representing that CheckedIn is the first non-OK element)
Any ideas how to do this?
I think this and other similar questions are completely legitimate programming questions (EDIT: see here: https://meta.stackexchange.com/questions/22922/which-site-do-excel-or-other-spreadsheet-formulas-belong-on/76767#76767). (It's probably a duplicate of some other StackOverflow question, though.)
You want to use an array formula:
=MATCH(TRUE,(StatusRange<>"OK"),0)
You need to enter this as an array formula, with Ctrl-Shift-Enter.
'MATCH' finds a value in a range or an array. Comparing a range to a scalar, as in '(StatusRange<>"OK")', returns an array of boolean values, so you're looking to match a value of 'TRUE'.
(The formula you posted was looking for a string literal with the value '<>"OK"'...)
If you ultimately want the value in the ProcessStep column, look at the help for the 'INDEX' or 'VLOOKUP' functions.