Excel - Is there a way to tell a cell to use a certain function based on the first letter of a another cell? - excel

I am creating a Product Decoder for a project.
Lets say, Our product can have a code such as "ABCDE" OR a code like "BCDEF".
ABCDE has a table of data that I use to decode using a lookup. For example AB can decode into "Potato" and CDE can decode into "Chip". So any combination with AB can be Potato "Anything else".
BCDER, BC can decode into "Veggie" so DER can code into "Chip".
I also use the 1/search method to take placements for the decode. Example =IFERROR(LOOKUP(2,1/SEARCH($E$19:$E$23,N18),$E$19:$E$23), "")
I concatenate all the decodes using =S2&" "&T2&" "&U2&" "&V2
Question is...if we are getting a huge amount of product code coming that I want to decode into one single column... How do I tell excel to use this table of data for ABCDE if product starts with "A", if not, use table of data that correlates to BCDER when product starts with "B".
Edit 1:
Here is my table, right side is where i look up the Part Number column N"
As you can see on column "W" I concatenate the date is Look up from columns O~V.
Column O Function: =IFERROR(LOOKUP(2,1/SEARCH($C$1:$C$7,N2),$C$1:$C$7), "")
On column N, I have two parts. One that starts with M and one that starts with K which is pretty standard.
Image two is me trying to use the IF Left but, it doesn't really work
=IF(LEFT(AA4,10) = "M ", W2, W18)
So How can I tell my excel page to use Table A1:A12 if part starts with "M*" and vice versa?
Let me know if this is confusing, I will do my best to clear things up.

First, a possible correction
I think this function does not give you what you say it does:
= IFERROR(LOOKUP(2,1/SEARCH($E$19:$E$23,N18),$E$19:$E$23), "")
You might mean:
= IFERROR( LOOKUP( 2, 1/SEARCH( $E$19:$E$23, N18 ), $F$19:$F$23 ), "" )
Because you want to look up the value in column E and return the value in column F. If that's not true, then skip the rest of this answer.
Now the solution
What you're trying to do is change the lookup array if the part number starts with a different letter. So, the IF( LEFT( combo mentioned by #BigBen should be used to modify the lookup array. I think it would look like this:
= IFERROR( LOOKUP( 2
,1/SEARCH( IF( LEFT( AA4, 1 ) = "M"
,$C$2:$C$12
,$C$19:$C$23 )
,N2 )
,IF( LEFT( AA4, 1 ) = "M"
,$D$2:$D$12
,$D$19:$D$23 )
)
,"")

Related

Excel Dynamic Array formula to create a running product of a column

I need to create a running product from a column of numbers (I could use a row, but a column is easier to demonstrate here.) The input might be any arbitrary array. In fact, in the application where I would deploy this, it will not be a range, but rather another dynamic array within a LAMBDA formula. Here is an example of the Input column of numbers and the desired Output from the formula:
Inputs
Expected Dynamic Array Output
10
10
8
80
3
240
4
960
5
4800
The formula would spill the results.
There are lots of solutions for a running total, but I've found no solution for a running product. I have tried a few different approaches, including SUBTOTAL and AGGREGATE with no success. I have also built a number of approaches that get the result, but are hard-coded to a fixed number of rows. I need the formula to adapt to any arbitrarily sized number of rows. The following formula is the closest I have gotten so far.
This LET formula delivers the result, but, as you can see is fixed to 5 rows:
=LET( a, {10;8;3;4;5},
v, SEQUENCE( ROWS(a) ), h, TRANSPOSE( v ),
stagr, (v - h + 1) * (v >= h),
m, IFERROR(INDEX( a, IF(stagr>0,stagr,-1), ), 1),
almost, INDEX(m,v,h) * INDEX(m,v,h+1) * INDEX(m,v,h+2) * INDEX(m,v,h+3) * INDEX(m,v,h+4),
result, INDEX( almost, , 1 ),
result )
The arbitrary array of numbers input is placed in the variable a.
The next step is to create some indexes that will be used to address these numbers: v is a sequence of vertical rows for each number in a and h is a the same sequence, but transposed into columns. stagr is an index matrix that is created from v and h that will later be used to address each item in a to form it into a multiplication matrix. If you replace the last result with stagr, you can see the shape of stagr. It just shifts a column down by one row until they are shifted all the way down.
Now we create the mulitplication matrix m using stagr by simply using INDEX, like this: INDEX(a,stagr). But this is not exactly what is needed because it takes the first row value (10) and replicates it because an INDEX of 0 is treated the same as 1. To get what we want, I forced an error by using and internal IF statement like this: INDEX( a, IF(stagr>0,stagr,-1) ) to replace the 0 results with -1. i.e. it will produce this:
Now, replace the errors with 1's by using IFERROR, so this explains how m is created and why. The result is a matrix like this:
and by multiplying m row-wise, we get the output we want, but this is where I fail.
For illustration, I created a variable almost that shows how I am trying to do a row-wise multiplication.
almost, INDEX(m,v,h) * INDEX(m,v,h+1) * INDEX(m,v,h+2) * INDEX(m,v,h+3) * INDEX(m,v,h+4)
You can see that I crudely multiplied one column times the next and the next... and using h + offset to get there. This produces the almost matrix and result just delivers the first column of that matrix, which contains the answer.
While an answer might be a good replacement for almost that would be dynamically sized, that is not my real question. I want a running product and I suspect that there is a wholly different approach than simply replacing my almost.
Just to be clear, the result must be a dynamic array that spills with no helper cells or CSE drag-down.
oh... and no VBA. (#stackoverflow - please add a no-VBA tag)
The only way I can find is to use DPRODUCT with OFFSET, but that requires a title row. It does not matter what is in the title row(it can even be empty), just that it is included.
=DPRODUCT(OFFSET(A1,0,0,SEQUENCE(COUNT(A:A),,2)),1,$ZZ1:$ZZ2)
The $ZZ1:$ZZ2 can be any empty cell reference.
If the values in A are dynamic then we can do:
=DPRODUCT(OFFSET(A1,0,0,SEQUENCE(ROWS(A2#),,2)),1,$ZZ:$ZZ)
There are plenty of interesting answers here. But, if summation is easy why not take logarithms of the number you want to multiply, sum those logarithms and then calculate the exponent of your sum to return to the product of the original numbers.
i.e. exploit the fact that ln(a * b) = ln(a) + ln(b)
Whilst not available to everybody (yet) we can use SCAN()
Formula in A1:
=SCAN(1,{10,8,3,4,5},LAMBDA(a,b,a*b))
The 1st parameter is our starting value, meaning the 1st calculation in the nested LAMBDA() is '1*10'.
The 2nd parameter can both take a 1D- & 2D-array (written or range-reference).
The 3rd parameter is a nested LAMBDA() where the result of our recursive function will then be used for the 2nd calculation; '10*8'. And the 3rd...etc. etc.
In the above sample a vertical array is spilled but when horizontal input is used this will obviously result in an horizontal spilled output. When a 2D-array is used this will spill a 2D-array as result.

(Excel 2013/Non-VBA) Format Data column based on value of another cell?

We have a column that is query driven, and the query partially formats the values in the column using math based off the value of a "user entry cell" on another sheet.
For the really curious, our query looks like this:
DECLARE #rotationsNum INT
SET #rotationsNum = ?
SELECT t.Piece_ID, t.Linear_Location, ((ROW_NUMBER() OVER(ORDER BY
Linear_Location) -1 )%#rotationsNum )*(360/#rotationsNum) AS Rotation FROM
(SELECT Position.Feature_Key, Piece_ID, ((Place-1)%(Places/#rotationsNum))+1 AS Linear_Location, Place, Measured_Value, Places FROM Fake.dbo.Position LEFT JOIN Fake.dbo.Features
ON Position.Feature_Key = Features.Feature_Key WHERE Position.Inspection_Key_FK = (SELECT Inspection_Key FROM Fake.dbo.Inspection WHERE Op_Key = ?)) AS t
ORDER BY Piece_ID, Linear_Location
The first parameter "#rotationsNum" is a cell that will always have a value between 1-4. IF the value is 1, the entire column will show "0"s, which we want to show as "N/A". However, it isn't as simple as "How to hide zero data.." Because if the "#rotationsNum" == 2, 3, or 4, there will still be 0 values in the column that need to be shown.
A "#rotationsNum" value of 2 will have the query write the column as such: example
So I am trying to come up with a way to format the column =IF(cell>1, do nothing, overwrite entire column to say "NA"). But I don't think it is that straight forward since the column is query driven.
My resolution was to format the column so that if the cell that drives the "#rotationsNum" parameter is below 2, then the whole column just gets "grayed out". It kind of makes it look like a redaction, and isn't as desirable as "NA", but it works for our purposes. Hopefully this solution helps someone else who stumbles upon this problem.

Extract number right from right of brackets

I have multiple items in a column that look like this:
1. (758,01) 1516,01€
2. (380,95) 761,90€
3. (480) 903,90€
4. (350,06) 700,06€
5. (344) 688,75€
6. (681,16) 1361,16€
And I wanted to know how can I do two things:
Extract the number between ( ) and the number next to ) without the € part so that the final result is for example: 1516,01 758,01
Thanks
There are a number of ways. You can use the MID formula to get get the numbers between (), likewise for the second half and just replace the € with a blank. This works if your data is in cell B2,
=MID(B2, FIND("(", B2)+1, FIND(")", B2)-2)
And
=SUBSTITUTE(RIGHT(B2, FIND(" ", B2)-1), "€", "")

Using tbl.Lookup to match just part of a column value

This question relates to the Schematiq add-in for Microsoft Excel.
Using =tbl.Lookup(table, columnsToSearch, valuesToFind, resultColumn, [defaultValue]) the values in the valuesToFind column have a consistent 3 characters to the left and then varying characters after (e.g. 908-123456 or 908-321654 - i.e. 908 is always consistent)
How can I tell the function to lookup the value based on the first 3 characters only? The expected answer should be the sum of the results of the above, i.e. 500 + 300 = 800
tbl.Lookup() works by looking for an exact match - this helps ensure it's fast but in this case it means you need an extra step to calculate a column of lookup values, something like this:
A2: =tbl.CalculateColumn(A1, "code", "x => LEFT(x, 3)", "startOfCode")
This will give you a new column that you can use for the columnsToSearch argument, however tbl.Lookup() also looks for just one match - it doesn't know how to combine values together if there is more than one matching row in the table, so I think you also need one more step to group your table by the first 3 chars of the code, like this:
A3: =tbl.Group(A2, "startOfCode", "amount")
Because tbl.Group() adds values together by default, this will give you a table with a row for each distinct value of startOfCode and the subtotal of amount for each of those values. Finally, you can do the lookup exactly as you requested, which for your input table will return 800:
A4: =tbl.Lookup(A3, "startOfCode", "908", "amount")

How to convert a matrix to a single column using Excel

I have the following matrix in Excel:
3 Columns: A, B, C
Row 1: a b c
Row 2: d e f
Row 3: ghi
What I need is a single column with all these values. The result should look like that:
a
b
c
d
e
f
g
h
i
The TRANSPOSE function doesn't work for that case. I tried out the INDIRECT function, but did not find a solution. I would rather prefer to handle it with standard Excel formulas than with a makro.
Any ideas?
Say we have:
In E1 enter:
=INDEX($A$1:$C$3,ROUNDUP(ROW()/3,0),IF(MOD(ROW(),3)=0,3,MOD(ROW(),3)))
and copy down to get:
Using similar formulas you can map any two dimensional table into a single row or single column. It is equally easy to map a single column or row into a table.
The answers above are quite good, but IMHO, the solution provided by Chip Pearson here (http://www.cpearson.com/excel/TableToColumn.aspx), is superior is most respects since it immediately/automatically:
1) Determines the Row/Col delim values on its own, and immediately works for rectangular, e.g. above one must explicitly enter 3 for num Cols and 3 for num Rows, and must also figure out which is which. Whereas Pearson's solution does this automatically (eg. rmf's comment/concern above).
2) Pearson provides both variants for Col-ordered and also Row-ordered.
For a generalized approach that will create an array, you can use:
=LET( Matrix, $A$1:$C$3,
rM, ROWS( Matrix ),
cM, COLUMNS( Matrix ),
cells, SEQUENCE( 1, rM * cM, 0 ),
INDEX( Matrix, INT( cells / cM ) + 1, MOD( cells, cM ) + 1 )
)
While this takes advantage of the LET function, it is used for readability. For those not using Excel365, it is possible to do this without LET, but it is just painful to read .
If you need the result to be delivered as a column, change the order of arguments in SEQUENCE
= LET( Matrix, $A$1:$C$3,
rM, ROWS( Matrix ),
cM, COLUMNS( Matrix ),
cells, SEQUENCE( rM * cM, 1 , 0 ),
INDEX( Matrix, INT( cells / cM ) + 1, MOD( cells, cM ) + 1 )
) )
Of course, A1:C3 can be any arbitrarily shaped array.
This was already covered in Item 2 from the very general
Excel: Formulas for converting data among column / row / matrix :
The top cell of your target range (say, $H$1) should contain
=INDEX($A$1:$C$3,INT((ROW()-ROW($H$1))/3)+1,MOD(ROW()-ROW($H$1),3)+1)
where $A$1:$C$3 cotains your source data.
Copy the formula downwards as needed.
You could also use
=OFFSET($A$1,INT((ROW()-ROW($H$1))/3),MOD(ROW()-ROW($H$1),3))
as metioned in the referred article.
I suggest you to check Excel unpivot option to perform your task.
Select your matrix
Go through the Get & Transform section in the Data tab and click From Table/Range
In the new Power Query Editor select the columns you want to unpivot
Go through the Any Column section in the Transform tab, click the arrow nearby Unpivot Columns and choose the best option (if you follow the step 3 you can click Unpivot only selected columns)
Close & Load
This process is useful especially for complex matrices.
Check the above link for further information
With the current version of Excel, I realized operations with matrix has improve greatly. For converting a matrix to a single column, I suggest combining INDEX and SEQUENCE Functions in the following way:
Matriz_to_Column_Formula:
=INDEX(matrix_range,
TRUNC((SEQUENCE(ROWS(matrix_range)*COLUMNS(matrix_range),1,0,1))/COLUMNS(matrix_range)+1,0),
MOD(SEQUENCE(ROWS(matrix_range)*COLUMNS(matrix_range),1,0,1),COLUMNS(matrix_range))+1)
If you want to remove empty spaces:
=FILTER(Matriz_to_Column_Formula, Matriz_to_Column_Formula<>"")
Here is a short explanation:
Index requires 3 things: matrix source, row and column. The row and column you calculate each time allows index to point at that specific element in your matrix source. Index would give you as many elements as you require, which is Rows*Columns.
Let me expand on Rows and Columns using SEQUENCE to navigate by each element:
Row:
TRUNC((SEQUENCE(ROWS(matrix_range)*COLUMNS(matrix_range),1,0,1))/COLUMNS(matrix_range)+1,0)
The formula SEQUENCE will generate as many elements as your matrix has, starting from 0 until Rows*Columns-1, and the division by columns will point only at a specific row. The +1 is used because sequence starts at 0 and INDEX Row element works from 1 to n. TRUNC is used only to get a integer number of the row.
Column:
MOD(SEQUENCE(ROWS(matrix_range)*COLUMNS(matrix_range),1,0,1),COLUMNS(matrix_range))+1
Here you apply the same principle, using SEQUENCE to generate as many elements as your matrix has from 0 to Rows*Columns-1, and by getting the remainder between the sequence and Columns you will point to the column you need to.
Alright, this is my first post, hope this helps anyone. Thanks for you help in many occasions!
Example in Excel:
Matrix to Single Column - Example in excel
Opt 1:
=INDEX(C3:E7,
TRUNC((SEQUENCE(ROWS(C3:E7)*COLUMNS(C3:E7),1,0,1))/COLUMNS(C3:E7)+1,0),
MOD(SEQUENCE(ROWS(C3:E7)*COLUMNS(C3:E7),1,0,1),COLUMNS(C3:E7))+1)
Opt 2:
=IF(INDEX(C3:E7,TRUNC((SEQUENCE(ROWS(C3:E7)*COLUMNS(C3:E7),1,0,1))/COLUMNS(C3:E7)+1,0),MOD(SEQUENCE(ROWS(C3:E7)*COLUMNS(C3:E7),1,0,1),COLUMNS(C3:E7))+1)="","",INDEX(C3:E7,TRUNC((SEQUENCE(ROWS(C3:E7)*COLUMNS(C3:E7),1,0,1))/COLUMNS(C3:E7)+1,0),MOD(SEQUENCE(ROWS(C3:E7)*COLUMNS(C3:E7),1,0,1),COLUMNS(C3:E7))+1))
Remove Empty:
=FILTER(INDEX(C3:E7,TRUNC((SEQUENCE(ROWS(C3:E7)*COLUMNS(C3:E7),1,0,1))/COLUMNS(C3:E7)+1,0),MOD(SEQUENCE(ROWS(C3:E7)*COLUMNS(C3:E7),1,0,1),COLUMNS(C3:E7))+1),
INDEX(C3:E7,TRUNC((SEQUENCE(ROWS(C3:E7)*COLUMNS(C3:E7),1,0,1))/COLUMNS(C3:E7)+1,0),MOD(SEQUENCE(ROWS(C3:E7)*COLUMNS(C3:E7),1,0,1),COLUMNS(C3:E7))+1)<>"")

Resources