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)<>"")
Related
I'm trying to compare two columns ("Shows") from different tables and showing which one has the greater number ("Rating") associated with it in another table.
Ignore the operation column above as part of the solution that I'm trying to get, it's just to illustrate for you what I'm trying to compare.
Important note: If the names are duplicated. Compare the matching pair in their corresponding order. (1st with 1st, 2nd with 2nd, 3rd with 3rd etc..) illustrated in the table below:
Thanks
You can try the following in cell F3 for an array solution that spills the entire result at once:
=LET(sA, A3:A6, rA, B3:B6, sB, C3:C6, rB, D3:D6, CNTS, LAMBDA(x,
LET(seq, SEQUENCE(ROWS(x)), MAP(seq, LAMBDA(s,ROWS(FILTER(x,(x=INDEX(x,s))
*(seq<=s))))))), cntsA, CNTS(sA), cntsB, CNTS(sB), eval, MAP(sA, rA, cntsA,
LAMBDA(s,r,c,IF(r > FILTER(rB, (sB=s) * (cntsB=c)), "Table 1", "Table 2"))),
HSTACK(sA, eval))
Here is the output:
Explanation
The main idea is to count repeated show values. We use a user LAMBDA function CNTS, to avoid repetition of the same formula twice. Once we have the counts (cntsA, contsB), we use MAP to iterate over Table 1 elements with the counts and look for specific show and counts to compare with Table 2 columns. The FILTER function will return always a single value (based on sample data). Finally, we prepare the output as expected using HSTACK.
Try-
=IF(INDEX(FILTER($B$3:$B$6,$A$3:$A$6=G3),COUNTIFS($G$3:$G3,G3))>INDEX(FILTER($E$3:$E$6,$D$3:$D$6=G3),COUNTIFS($G$3:$G3,G3)),"Table-1","Table-2")
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.
I have a spreadsheet that is using the SUMIF function. It works very well to summarize single values from another column but I want to be able to potentially multiply a single entries value before summing it.
I'm unable to attach photos so I'll try to describe. My spreadsheet has this equation on it:
=SUMIF(L25:L31,"x",$K$25:$K$31)
Then if I put an 'x' on a row in column 'L' it will include the value from column 'K' in the summation. I want to be able to use 'x2', 'x3', 'x4', etc. and multiply the value before the summation. Is that possible with Excel?
Multiplication is distributive; the product of the sum is the same as the sum of the products. So you can move the multiplier to the outside of the equation if I am understanding your question correctly. Where "y" is the multiplier and "x" is the criteria you are looking up, the below should work:
=y*SUMIF(L25:L31,"x",$K$25:$K$31)
If the multiple is a variable, then I would suggest adding helper columns, and simply change the sum range on the SUMIF formula.
Note that the SUMPRODUCT suggested does not take into account the conditional nature of the sum that I assume you are looking for (otherwise why would you use SUMIF instead of SUM?)
This should do the trick:
=SUMPRODUCT(IFERROR($K$25:$K$31*IF($L$25:$L$31="x",1,MID($L$25:$L$31,2,255)),0))
But must the "x" be there? If you have the flexibility to switch to 1, 2, 3 instead of x, x2 and x3, that would open up to simplify the formula to this
=SUMPRODUCT($K$25:$K$31*$L$25:$L$31)
The latter should be more efficient as well, in case your actual data is large.
If I've not misunderstood, this would produce the result of applying a variable multiplier to the qualified data points and then sum it up:
=SUM( (L25:L30="x") * K25:K30 * {1;2;3;4;5;6} )
The 1;2;3... column array is arbitrary - I just invented it for example. If it really is an incremental sequence, then you can produce the same this way and gain the advantage that it is easier to extend (without typing lots of numbers):
=SUM( (L25:L30="x") * K25:K30 * SEQUENCE( ROWS(L25:L30) ) )
If this is the solution and you really want to streamline it, then make it a little cleaner with LET:
=LET( sumRange, K25:K30,
criteriaRange, L25:L30,
criteria, "x",
size, MIN( ROWS( criteriaRange), ROWS( sumRange ) ),
SUM( (criteriaRange = criteria ) * sumRange * SEQUENCE( size ) ) )
If the multipliers are not an incremental sequence, then a third variable could be introduced to replace SEQUENCE( size ) that would contain the multiplier array.
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 )
)
,"")
The formula I would like to use looks something like this: SUMPRODUCT(x^(1:n),y^(n:1)). n=values in column A. 1:n is the exponents in forward progression from 1 to n in steps of 1. n:1 is the exponents in reverse progression from n to 1 in steps of 1. I would like the formula to be dynamic to fill in column B with the n values based on column A.
Try:
=SUMPRODUCT(5^ROW(1:100))
Or in Excel O365
=SUM(5^ROW(1:100))
As per #RonRosenfeld, a more sturdy solution could be =SUM(5^SEQUENCE(100)) in Excel 365.
EDIT: Based on OP's comments he could use (no O365):
=SUMPRODUCT(5^ROW(A1:INDEX(A:A,COUNTA(A:A))),7^LARGE(ROW(A1:INDEX(A:A,COUNTA(A:A))),ROW(A1:INDEX(A:A,COUNTA(A:A)))))
You can store the powers in a column and use the array formula:
SUM((A1:A100)^$B$1) where A column contains 5 in each cell and B column contains the range of powers you want to use. You can use an array formula in the different cell to get the answer.
Use the SERIESSUM function
The Excel SERIESSUM function returns the sum of a power series, based on the following power series expansion:
Power Series Equation
The syntax of the function is:
SERIESSUM( x, n, m, coefficients )
Where the function arguments are:
x - The input value to the power series.
n - The first power to which x is to be raised.
m - The step size that n is increased by, on each successive power of x.
coefficients - An array of coefficients that multiply each successive power of x.
The number of values in the supplied coefficients array defines the number of terms in the power series. This is illustrated in the following examples.
Example 1:
In the spreadsheet below, the Excel Seriessum function is used to calculate the power series:
5^1 + 5^2 + 5^3 + 5^4 + 5^5
formula: =SERIESSUM( 5, 1, 1, {1,1,1,1,1} )
output = 3905
Example 2:
1 * 2^1 + 2 * 2^3 + 3 * 2^5 + 4 * 2^7 + 5 * 2^9
formula: =SERIESSUM( 2, 1, 2, {1,2,3,4,5} )
output = 3186
I hope this is of help.
An Alternative Answer again. I think the correct for your case :-)
Using the SERIESSUM function allows the use of different coefficients therefore the reason for the use of the coefficients in an array. But because the coefficients are the same then this is simply a geometric progression.
The following formula will do that for you:
=n+n*(n)^(1)*(1-(n)^c)/(1-n)
where "n" is the number (5) and "c" is the number of the series (100)
This becomes:
=5+5*(5)^(1)*(1-(5)^100)/(1-5)
=SUMPRODUCT(5^ROW(A1:INDEX(A:A,COUNTA(A:A))),7^LARGE(ROW(A1:INDEX(A:A,COUNTA(A:A))),ROW(A1:INDEX(A:A,COUNTA(A:A)))))
This formula worked flawlessly!!!
Thank you #JvdV and everyone else for your efforts in helping me! GREATLY APPRECIATED!