Reversing a list in Excel within a formula - excel

So there are a bunch of ways to reverse a list to turn it into a new list, using helper columns. I've written some code that does use helper columns to reverse a list and then use it.
I'm wondering how I would reverse a list without using a helper column for use in a sumproduct - for example,
=sumproduct(Reverse(A1:A3),B1:B3)

This array formula will reverse the order of a vertical array:
= INDEX(B18:B21,N(IF({1},MAX(ROW(B18:B21))-ROW(B18:B21)+1)))
Also, this reverses a horizontal array:
= INDEX(A1:D1,N(IF({1},MAX(COLUMN(A1:D1))-COLUMN(A1:D1)+1)))
EDIT
More generally, to vertically flip a matrix instead of just an array (which is just a one-dimensional matrix), use this array formula: (e.g. for range A1:D2)
= INDEX(A1:D2,N(IF({1},MAX(ROW(A1:D2))-ROW(A1:D2)+1)),
N(IF({1},COLUMN(A1:D2)-MIN(COLUMN(A1:D2))+1)))
And to horizontally flip a matrix, use this:
= INDEX(A1:D2,N(IF({1},ROW(A1:D2)-MIN(ROW(A1:D2))+1)),
N(IF({1},MAX(COLUMN(A1:D2))-COLUMN(A1:D2)+1)))
And a bonus... to flip a matrix horizontally and vertically in one shot (i.e. rotate it 180 degrees):
= INDEX(A1:D2,N(IF({1},MAX(ROW(A1:D2))-ROW(A1:D2)+1)),
N(IF({1},MAX(COLUMN(A1:D2))-COLUMN(A1:D2)+1)))
Actually this last one here could more generally be used to flip either a horizontal or vertical array.

This will do what you are asking:
=SUMPRODUCT(INDEX(A:A,N(IF(1,{3;2;1}))),B1:B3)
To make a little more dynamic you can use this array formula:
=SUM(INDEX(A:A,N(IF(1,LARGE(ROW(A1:A3),ROW(A1:A3)))))*B1:B3)
Being an array formula, it needs to be confirmed with Ctrl-Shift-Enter, instead of Enter when exiting Edit mode.

Found an easy solution that works in the latest Excel versions:
=SORTBY(*rowarray*, column(*rowarray*),-1)
=SORTBY(*columnarray*, row(*columnarray*),-1)

For what it's worth, here's another completely different method to reverse an array. (I'm posting this as a separate answer just because it is apples and oranges to the other answer I already provided.)
Instead of reversing the order of the array by reversing the indexing, it is also possible to use matrix multiplication (MMULT) to accomplish this.
If your data in A1:A3 is {1;3;5} (for example) then the following matrix multiplication effectively reverses this array:
[0 0 1] [1] [5]
[0 1 0] * [3] = [3]
[1 0 0] [5] [1]
In order to generate that matrix of 1's and 0's above, you can do this (line break added for readability):
= (ROW(INDEX(A:A,1):INDEX(A:A,ROWS(A1:A3)))=
(COLUMN(INDEX(1:1,ROWS(A1:A3)))-COLUMN(INDEX(1:1,1):INDEX(1:1,ROWS(A1:A3)))+1))+0
So in the end, the formula to reverse this array would be:
= MMULT((ROW(INDEX(A:A,1):INDEX(A:A,ROWS(A1:A3)))=
(COLUMN(INDEX(1:1,ROWS(A1:A3)))-COLUMN(INDEX(1:1,1):INDEX(1:1,ROWS(A1:A3)))+1))+0,A1:A3)
This same line of thinking can be used to reverse a horizontal array. For example if A1:C1 is {1,3,5}, then:
[0 0 1]
[1 3 5] * [0 1 0] = [5 3 1]
[1 0 0]
Note how the matrix of 1's and 0's is the second argument this time instead of the first argument.
Using the same general line of reasoning, you can get to this formula to reverse a horizontal array.
= MMULT(A1:C1,(ROW(INDEX(A:A,1):INDEX(A:A,COLUMNS(A1:C1)))=
(COLUMN(INDEX(1:1,COLUMNS(A1:C1)))-COLUMN(INDEX(1:1,1):INDEX(1:1,COLUMNS(A1:C1)))+1))+0)
This method has two major disadvantages as compared two the N(IF(...)) solution, namely:
It's way longer.
It only works for numbers since MMULT requires numbers, but the other method works if the cells contain anything (e.g. text).
I was using this solution to reverse arrays without helper columns until just recently when I learned about the N(IF(...)) alternative.

Actually you can make the formula in your Question work (with a small UDF()):
Pick a cell and enter:
=SUMPRODUCT(reverse(A1:A3),B1:B3)
with this in a standard module:
Public Function reverse(rng As Range)
Dim ary(), N As Long, i As Long
N = rng.Count
ReDim ary(1 To N)
i = N
For Each r In rng
ary(i) = r.Value
i = i - 1
Next r
With Application.WorksheetFunction
reverse = .Transpose(ary)
End With
End Function

With Dynamic Arrays
This is the best solution I have found.
=SORTBY(list,SEQUENCE(ROWS(list),1,ROWS(list),-1))
https://exceljet.net/formula/reverse-a-list-or-range

=INDIRECT(ADDRESS(ROW()+COUNTA(A1:$A$3)+1-ROW(A1),1))

Related

Excel: How to find closest number in table, many times

Excel
Need to find nearest float in a table, for each integer 0..99
https://www.excel-easy.com/examples/closest-match.html explains a great technique for finding the CLOSEST number from an array to a constant cell.
I need to perform this for many values (specifically, find nearest to a vertical list of integers 0..99 from within a list of floats).
Array formulas don't allow the compare-to value (integers) to change as we move down the list of integers, it treats it like a constant location.
I tried Tables, referring to the integers (works) but the formula from the above web site requires an Array operation (F2, control shift Enter), which are not permitted in Tables. Correction: You can enter the formula, control-enter the array function for one cell, copy the formulas, then insert table. Don't change the search cell reference!
Update:
I can still use array operations, but I manually have to copy the desired function into each 100 target cells. No biggie.
Fixed typo in formula. See end of question for details about "perfection".
Example code:
AI4=some integer
AJ4=MATCH(MIN(ABS(Table[float_column]-AI4)), ABS(Table[float_column]-AI4), 0)
repeat for subsequent integers in AI5...AI103
Example data:
0.1 <= matches 0
0.5
0.95 <= matches 1
1.51 <= matches 2
2.89
Consider the case where target=5, and 4.5, 5.5 exist in the list. One gives -0.5 and the other +0.5. Searching for ABS(-.5) will give the first one. Either one is decent, unless your data is non-monotonic.
This still needs a better solution.
Thanks in advance!
I had another problem, which pushed to a better solution.
Specifically, since the Y values for the X that I am interested in can be at varying distances in X, I will interpolate X between the X point before and after. Ie search for less than or equal, also greater than or equal, interpolate the desired X, then interpolate the Y values.
I could go a step further and interpolate N - 1 to N + 1, which will give cleaner results for noisy data.

Sum rows (or columns) of a 2d matrix into a 1d array in an Excel formula

Is there any way to tell specify to Excel that it should perform a per-row calculation within a 2d matrix? For instance, if I have an array defined
{1,0,0;0,0,1;1,0,1}
i.e.
1 0 0
0 0 1
1 0 1
Is there a formula that can allow me to operate on the array {1;1;2}?
The eventual goal in this would most likely to be to further transform that array using an expression such as {1;1;2}>=2 or MATCH(2,{1;1;2},0), but the important thing isn't so much what the outer expression is as that the transformation takes place at all.
Of course, much of this can in many cases be outsourced to operations on a helper column, but there are numerous times when solving a problem with space feels like an inelegant approach.
MMULT would do what you wants.
{=MMULT({1,0,0;0,0,1;1,0,1},{1;1;1})}
used as array formula (CSE) results in {1;1;2}.
1,0,0 1 1*1+0*1+0*1 = 1
0,0,1 x 1 = 0*1+0*1+1*1 = 1
1,0,1 1 1*1+0*1+1*1 = 2
When MMULT is wrapped in other functions which take their parameters as arrays, there may not be the need for pressing Ctrl+Shift+Enter. For example
=MATCH(2,MMULT({1,0,0;0,0,1;1,0,1},{1;1;1}),0)
results in 3 without entering the formula using Ctrl+Shift+Enter.

Summing a Product in Excel, over the same parameters

I've been struggling with something in excel which is quite easy to do individual cases of using an array, but I want to do in a single cell.
Effectively, in row C I have the multipliers I need, lets call them i_k, for j from 1 to n. The equation I want to calculate in mathematical notation is;
Sigma(from j = 0 to n) (Pi(from k = j to n) (i_k))
But I'm not quite sure how best to go about this. Effectively it should be;
(i_1)^n + (i_2)^(n-1) + (i_3)^(n-2) + ...
In the end. Any help?
I dont know if this is an elegant solution but I think this might solve it for you.
The key is to make a table so that your formulas continue.
The screenshot I have taken explains the formula I have used with its explanation I have used on top of it.
-- The first column will have the intended values of I
-- The second column's first row will have the value of N
-- The third column will have a formula which says:
=IF(ISNUMBER([#[Values of N]]),[#[Values of N]],C2-1)
This will give you the decreasing value of N
Now just multiply N with I on the 4th column using a simple multiplication and add the final result:

masking a double over a string

This is a question in MatLab...
I have two matrices, one being a (5 x 1 double) :
1
2
3
1
3
And the second matrix being a (5 x 3 string), with spaces where no character appears :
a
bc
def
g
hij
I am trying to get an output such that a (5 x 1 string) is created and outputs the nth value from each line of matrix two, where n is the value in matrix one. I am unsure how to do this using a mask which would be able to handle much larger matrces. My target matrix would have the following :
a
c
f
g
j
Thank you very much for the help!!!
There are so many ways you can accomplish this task. I'll give you two.
Method #1 - Generate linear indices and access elements
Use sub2ind to generate a set of linear indices that correspond to the row and column locations you want to access in your matrix. You'll note that the column locations are the ones changing, but the row locations are always increasing by 1 as you want to access each row. As such, given your string matrix A, and your columns you want to access stored in ind, just do this:
A = ['a '; 'bc '; 'def'; 'g ';'hij'];
ind = [1 2 3 1 3];
out = A(sub2ind(size(A), (1:numel(ind)).', ind(:)))
out =
a
c
f
g
j
Method #2 - Create a sparse matrix, convert to logical and access
Alternatively, you can create a sparse matrix through sparse where the non-zero entries are rows vary from 1 up to as many elements as you have in ind and the columns vary like what you have given us.
S = sparse((1:numel(ind)).',ind(:),true,size(A,1),size(A,2));
A = A.'; out = A(S.');
Be mindful that you are trying to access each element in a row-major fashion, yet MATLAB will do this in a column-major format. As such, we would need to transpose our data matrix, and also take our sparse matrix and transpose that too. The end result should give you the same order as Method #1.

Can you convert a scalar into an arbitrary length array in excel

The reason I'm doing this is so I don't have to use matrix multiplication and can use sumproduct instead. I can do it with matrix multiplication, but I'd rather not have the overhead of explaining what that is and how to do it to my colleagues. I need to apply a scalar to two arrays that I'm applying a sumproduct against. The problem is that since the scalar is length 1, it breaks the sumproduct formula.
Here is what the formula looks like:
=sumproduct(1/sumif(conditionals), array 2, array 3)
What I would like to do is scale the first array, which is my scalar, based on the size of the other 2 arrays. I have tried this, which I figured wouldn't work, but it should get the idea of what I'm trying to accomplish across:
=sumproduct(rept(1/sumif(conditionals),count(array 2)), array 2, array 3)
The problem here is that the rept function returns a string, which I'm unable to use round() or any other formulas I can think of to make into an 1xN array of that scalar. I should note I'm not trying to cast the variable necessarily, but if there is a way to do that it would likely solve the problem.
Any ideas?
Have you tried?
=sumproduct((1/sumif(conditionals))*'array 2'*'array 3')
In addition, wouldn't that be mathematically the same as
=(1/sumif(conditionals))*sumproduct('array 2','array 3')
The following formula should solve your problem:
=SUMPRODUCT(
ROW(INDIRECT("1:" & COUNT(array 2))) ^ 0 / SUMIF(conditionals),
array 2,
array 3
)
This works as follows:
First obtain the number of elements of array 2:
COUNT(array 2)
Then convert it into a 'virtual' range reference (only rows):
INDIRECT("1:" & COUNT(array 2))
Then determine the row numbers from this virtual range reference, the result of which is {1,2,...,COUNT}:
ROW(INDIRECT("1:" & COUNT(array 2)))
Finally, convert the row number by raising to the power 0:
ROW(INDIRECT("1:" & COUNT(array 2))) ^ 0
This gives you the desired array {1,1,...,1} with COUNT elements, which can be used in the SUMPRODUCT() function.

Resources