I would be grateful if anyone knows whether the following issue is documented and/or what the underlying reasons are.
Assuming we have, for example, the numbers from 1 to 10 in A1:A10, the following formula
=SUMPRODUCT(SUBTOTAL(4,OFFSET(A1,{0;5},0,5)))
is perfectly valid and is equivalent to taking the sum of the maximum values from each of the ranges A1:A5 and A6:A10, since the OFFSET function, here being passed an array of values ({0;5}) as its rows parameter and with the appropriate height parameter (5), resolves to the array of ranges:
{A1:A5,A6:A10}
which is then passed to SUBTOTAL to generate a further array comprising the maximum values from each of those ranges, i.e. 5 and 10, before being summed by SUMPRODUCT.
AGGREGATE was introduced in Excel 2010 as, it would seem, a more refined version of SUBTOTAL. My question is why, when attempting the following
=SUMPRODUCT(AGGREGATE(14,,OFFSET(A1,{0;5},0,5),1))
which should be equivalent to the SUBTOTAL example given above, does Excel display the message that it "Ran Out of Resources While Attempting to Calculate One or More Formulas" (and return a value of 0)?
(Note that users of a non-English-language version of Excel may require a different separator within the array constant {0;5}.)
This is a quite unexpected error. Evidently the syntax is not at fault, nor is the passing of the OFFSET construction 'disallowed'. With nothing else in the workbook, what is causing Excel to use so much resource when attempting to resolve such a construction?
A similar result occurs with INDIRECT instead of OFFSET, i.e.
=SUMPRODUCT(SUBTOTAL(4,INDIRECT({"A1:A5","A6:A10"})))
is perfectly valid, yet
=SUMPRODUCT(AGGREGATE(14,,INDIRECT({"A1:A5","A6:A10"}),1))
gives the same error described above.
Regards
[Not enough reputation to add a comment.]
Excel on Mac returns this:
Arrays containing ranges are not supported
The AGGREGATE error appears to be due to passing an array of range references to an argument that expects an array of values. The error message has symptoms of passing an unitialized pointer resulting in unexpected behavior. Indeed, the same error dialog is shown with some other functions like:
=MEDIAN(TRANSPOSE(INDIRECT({"a1:a5","a6:a10"})))
On the other hand, passing an array of references to the fourth or later argument of AGGREGATE is permitted, eg:
=SUMPRODUCT(AGGREGATE(4,,B1,INDIRECT({"a1:a5","a6:a10"})))
In a similar way, SUBTOTAL allows arrays of references in the second or later arguments, none of which natively take arrays. The SUBTOTAL formula is evaluated by applying the function to each range reference in the array, i.e.:
SUBTOTAL(4,INDIRECT({"a1:a5","a6:a10"}))
->{SUBTOTAL(4,A1:A5),SUBTOTAL(4,A6:A10)}
Formatting arrays and range references within function definitions may help with visualising the formula processing:
AGGREGATE(function_num, options, array or ref1, [k or ref2], [ref3], …)
SUBTOTAL(function_num, ref1, [ref2],...)
Note that reference only arguments also allow for arrays of references.
It will be interesting to see if there are any changes to this behavior with the updated calc engine and dynamic arrays currently in Office 365 preview and due for release soon...
Related
How to RANK an array directly? I would like to avoid creating more intermediate data in cells just to reference them.
Excel RANK.AVG formula states it accepts both array and reference:
Syntax
RANK.AVG(number,ref,[order])
The RANK.AVG function syntax has the following arguments:
Number Required. The number whose rank you want to find.
Ref Required. **An array of, or a reference to**, a list of numbers. Nonnumeric values in Ref are ignored.
Order Optional. A number specifying how to rank number.
But Excel keeps rejecting the below formula.
=RANK.AVG(5, {3,1,7,10,5})
If the numbers are put in cells, say B1:B5, Excel accepts
=RANK.AVG(5, B1:B5}
Ultimately, I would like to rank a dynamic array
=RANK.AVG(value, TOCOL(VSTACK(array1, array2))
e.g. =RANK.AVG(5, TOCOL(VSTACK(B1:B5,C1:C10))
It seems that the official documentation on the various RANK functions is simply wrong with respect to the fact that they permit arrays for the ref argument (see here, for example).
You will have to come up with creative alternatives which mimic the RANK.AVG function, for example:
=LET(ζ,SORT(MyArray,,-1),AVERAGE(FILTER(SEQUENCE(COUNT(ζ)),ζ=MyValue)))
I am having difficulty figuring out how to get the correct data type evaluated as a single array passed to the first argument of the Small() in this function. My overall goal is (completely without the use of helper cells) to combine two sets of ranges passed to Small() as arrays into a 2-dimensional array output. The formulas work correctly when placed separately in ranges, but when combined in a Let() I get type inconsistency caused #VALUE! errors as the output.
Here is the LET() function ...
=LET(
A1v, SEQUENCE(1,10,1,0),
A2v, SEQUENCE(1,10,2,0),
SMALL((A1v,A2v),SEQUENCE(2,COLUMNS(A1v)))
)
When the Let() formula is broken into pieces and placed into separate ranges as described below it produces the desired output in A3:J4 (A3#) as shown in this
Range A1 formula:
=SEQUENCE(1,10,1,0)
Range A2 formula:
=SEQUENCE(1,10,2,0)
Range A3 formula:
=SMALL((A1#,A2#),SEQUENCE(2,COLUMNS(A1#)))
I am aware that there are other function constructs that can be used to combine ranges. I am not looking for alternatives to using Small(). I am looking for answers that will help further my understanding of constructing arrays from and to be used as inputs to the new array functions in Excel. Thanks to everyone in advance!
The reason your Let function fails is the (A1v,A2v) parameter to Small. That construct is the Union Operator for Ranges. A1v and A2v are arrays, not ranges.
This can be seen in the Formula Evaluator dialog
In contrast (A1#,A2#) works because A1# and A2# are ranges.
FWIW, Small itself can accept either ranges or arrays
To solve this you'll need a general purpose solution to getting the Union of two data sets, whether they be Ranges or Arrays. This can be achieved using a Lambda function.
Add a Workbook scoped Name to the Name Manager, lets call it Union
In the Refers To section insert
=LAMBDA(tabl1, tabl2,
LET(rowindex, SEQUENCE(ROWS(tabl1)+ROWS(tabl2)),
colindex, SEQUENCE(1,COLUMNS(tabl1)),
IF(rowindex<=ROWS(tabl1),
INDEX(tabl1,rowindex,colindex),
INDEX(tabl2,rowindex-ROWS(tabl1),colindex)
)
)
)
Union is now available to use as a stand alone function, or imbedded in another function
Your Formula now becomes
=LET(
A1v, SEQUENCE(1,10,1,0),
A2v, SEQUENCE(1,10,2,0),
SMALL(Union(A1v,A2v),SEQUENCE(2,COLUMNS(A1v)))
)
Or without Lambda
=LET(
A1v, SEQUENCE(1,10,1,0),
A2v, SEQUENCE(1,10,2,0),
rowindex, SEQUENCE(ROWS(A1v)+ROWS(A2v)),
colindex, SEQUENCE(1,COLUMNS(A1v)),
Av, IF(rowindex<=ROWS(A1v),
INDEX(A1v,rowindex,colindex),
INDEX(A2v,rowindex-ROWS(A1v),colindex),
SMALL(Av,SEQUENCE(2,COLUMNS(A1v))) )
)
Untested, so you might have to tweak it a bit
The problem:
I need to read a row of values from an excel spreadsheet into a parameter array and use these values to set the initial values of stocks.
The specifics:
a. I can successfully set the scalar parameters default values from excel using ExcelControlName.getCellNumericValue("ExcelSheetName", RowNumber, ColumnNumber).
b. Trying to set default values for array parameters with ExcelControlName.readHyperArray(DestinationArrayName,"ExcelSheetName",RowNumber, ColumnNumber, false) returns a "Cannot return a void result" error on build.
c. I can read the parameter arrays from a function called from the Agent actions "On startup:" section using ExcelControlName.readHyperArray(DestinationArrayName,"ExcelSheetName",RowNumber, ColumnNumber, false).
d. Stocks with their initial values set to the parameter array that was successfully loaded by the function are all zero even though the parameter array shows values (when run). Initial value: ParameterArrayName.
e. When I set the parameter array values through the value editor the stocks initialize correctly.
My suspicion:
I'm thinking that the issue has something to do with the internal timing within the entrails of the model generated by Anylogic such that the function to load the parameters is executed after the stocks get initial values - but that could just be the delirium caused by repeatedly smashing my forehead into the wall. But, if this is indeed the case, how can I sneak the function in earlier or, better yet, how would someone who actually knows what they're doing accomplish this?
What I'm trying to accomplish:
As a septuagenarian with lots of time on my hands and a vague recollection of dynamic modeling using Dynamo from a Systems Science program in the early seventies (and not used since), I thought I'd take a whack at age-based modeling of the COVID-19 pandemic. I wanted to see, among other things, whether establishing elder-prisons (in now vacant Club-Meds, Sandals... I'm sure) would be an economically advantageous strategy. Getting there requires dis-aggregating classic SIR approaches into age-specific chains of causality. So far, I'm at 27 age-specific parameters for eight age-groups and 24 scalar parameters. As much as I'd like to type and retype... all this data I'm really hoping there is a better way.
I must say that I am amazed at how far modeling has come in only 50 or so years and I am enthralled with Anylogic's application - even though it's a bit java-ish for me.
Thank you ever so much,
Carl Cottrell
Equivalent parameter arrays - one with values entered in edit the other read from excel file through a function
Not sure if I understand but here it goes:
I understand that you have the following structure:
and you want to initialize the stock as follows.
To do that, on the initial value of your parameter use a function that returns an HyperParameter:
the function getInitialValue should return an HyperParameter and I think this code should work for you (you have to choose RowNumber according to whatever is on your excelfile, MyDimension is the name of your dimension, and ExcelControlName is the excel in which you hold the values of the initial values of the stock)
HyperArray x=new HyperArray(MyDimension);
for(int i=0;i<=numColumns;i++){
x.set(ExcelControlName.getCellNumericValue("ExcelSheetName", RowNumber, i), i);
}
return x;
I am struggling with an array formula, that logically seems sound, however it doesn't appear to be working correctly. I have been working on a complex sheet, that is not to include VBA, which has made it formula heavy, and using arrays instead.
In the image below, the first part is the problem, for the data shown in columns A-F, I wish to get a sum of the values that match the values in I1:K1.
The formula I have used to begin with can be seen in the first image also, this evaluates, pressing F9, to give me the desired output 20,40 & 50. However when I add the SUM around the formula, I only get the first result out.
I think this is an issue with me not seeing the wood for the trees on this one.
Thanks in advance.
This array formula seems to work:
=SUM((IFERROR(MATCH(A1:F1,I1:K1,0),0)>0)*A2:F2)
There are probably multiple better formulas to achieve the same thing.
But to talk about why this fails:
It is because of the OFFSET function returns a reference rather than a value. And so used in this array formula it returns an array of references {B2,D2,E2} instead of an array of values {20,40,50} which leads to the problem.
If you are using:
=SUMPRODUCT(OFFSET(A2,0,MATCH($I$1:$K$1,$A$1:$F$1,0)-1))
then using Evaluate Formula, you will get:
SUMPRODUCT({#VALUE,#VALUE,#VALUE})
in next to last step and 0 as the result. So the OFFSET leads to error values because of it returns an array of references which will not be dereferenced automatically and so will become #VALUE error each.
If you are using
=SUMPRODUCT(N(OFFSET(A2,0,MATCH($I$1:$K$1,$A$1:$F$1,0)-1)))
then it works and returns 110. So the N dereferences the references of each OFFSET and so the whole formula leads to an array of values {20,40,50} in sum.
{=SUM(N(OFFSET(A2,0,MATCH($I$1:$K$1,$A$1:$F$1,0)-1)))}
works too.
These problems occur using funktions like OFFSET and INDIRECT, which returns references rather than values, in array formulas. And having a dereferencing function around the OFFSET or INDIRECT stops the problems.
It is the same with:
=SUMPRODUCT(INDIRECT("R2C"&MATCH(I1:K1,A1:F1,0),FALSE))
versus
=SUMPRODUCT(N(INDIRECT("R2C"&MATCH(I1:K1,A1:F1,0),FALSE)))
I am interested in spreadsheet functions, not VBA solutions, to be included in a single cell formula.
[A1:A15 contain numeric values from 1 to 127, B1:B15 contain integers from 1 to 7 that set a divisor.]
Given the function:
=SUMPRODUCT(MOD(FREQUENCY(A1:A15;A1:A15);B1:B15))
FREQUENCY(A1:A15;A1:A15) gives a 1-column array of 15+1 rows, whereas the second part (B1:B15) is a 1-column array of 15 rows.
I would like to change the resulting array given by FREQUENCY (only in memory -not explicit in sheet-) from a 1-column 16 rows array to a 1-column 15 rows array with the first 15 cell values of that array.
[FREQUENCY documentation: https://support.office.com/en-us/article/FREQUENCY-function-44e3be2b-eca0-42cd-a3f7-fd9ea898fdb9 NB: for Excel, second remark states number of elements that depend on bins_array. ]
I would appreciate suggestions.
Thus, both arrays within MOD will have the same dimensions and SUMPRODUCT will not find cells with error values. I can disregard error values using IF and ISERROR within SUMPRODUCT, but I'd rather disregard the non-relevant part of the FREQUENCY resulting array if it is possible.
It has been thought that making it more specific might be more helpful, so it has been heavily reduced and simplified.
With external help, I have been able to fine-tune a way to solve my problem using INDEX in array formula mode. I am posting the answer in case it helps others.
One way: Put FREQUENCY(A1:A15;A1:A15), or any formula that produces an multi-cell array, within INDEX and have 2nd and/or 3rd arguments as array of consecutive values which will represent rows/columns.
INDEX(FREQUENCY(A1:A15;A1:A15);ROW(INDIRECT("1:" & ROWS(FREQUENCY(A1:A15;A1:A15)-1));1)
First argument within INDEX is the resulting array coming from a formula to shrink (from 16x1 to 15x1), which would be a multi-cell array formula if explicitly entered; second argument is the array 1..15 given by row numbers from 1 to the number of total rows of the "array from formula to shrink" MINUS 1: the first 15 (out of 16) values in the array from a formula; 3rd argument is the column of the shrank array (if need be, more than one could be selected using an analogue to the second argument).
In the particular case of FREQUENCY, because it is known that we are interested in the "bins" part of the function, the formula can be simplified by including the total rows of the "bins"/"intervals" array inside FREQUENCY (its second argument). We will have
INDEX(FREQUENCY(A1:A15;A1:A15);ROW(INDIRECT("1:" & ROWS(A1:A15)));1)
and the complete formula would become
SUMPRODUCT(MOD(INDEX(FREQUENCY(A1:A15;A1:A15);ROW(INDIRECT("1:" & ROWS(A1:A15)));1);B1:B15))
Now, both dividend and divisor of MOD have exactly the same dimensions (15x1) and because B1:B15 includes integers greater than 0 there are no errors.
Thanks all for helping me in making question more concise and better formatted.
ADDITIONAL INFORMATION: As pointed out correctly in comments by XOR LX, this does not seem to work in the widely popular spreadsheet software Excel. It has been developed for an INDEX function inside SUMPRODUCT as used in Open Office Calc which I had mistakenly thought 100% equivalent to Excel's version. A more complete answer perhaps using other functions would be appreciated.
In the previous answer, XOR LX points out very correctly that this formula cannot work in Excel, due to row_num/column_num argument behaviour. Very kindly XOR LX has shown me how that approach can work, and also thanks and credit for supplying a good answer: "INDEX can be used to redimension array (even dynamically created ones) if the row_num/column_num array is coerced to take an arbitrary array with the right dimensions, as shown on this blog entry " The following formula has been checked in Excel 2010 and has the expected results:
SUMPRODUCT(MOD(INDEX(FREQUENCY(A1:A15,A1:A15),N(INDEX(ROW(INDIRECT("1:" & ROWS(A1:A15))),,)),1),B1:B15))
NB: row_num argument of first INDEX, a ROW generated auxiliary array, has been nested inside N(INDEX([...],,)); at least one comma is necessary to account for the two arguments minimum of the nested INDEX. It is in itself interesting the discussion that applies generally to INDEX's arguments, and other functions', that need to be coerced to take arrays (see, here and here at XOR LX's blog). For Open Office users it might be worth stressing the point made at the blog
Unlike OFFSET, (...) for which the first parameter must be a
reference (...) in the worksheet, INDEX can also accept –
and manipulate – for its reference arrays which consist of values
generated e.g. via other subfunctions within the formula. XOR LX's blog
That would be indeed the case in changing the dimension in an array as in this question, but also useful in reversing or displacing the values in an array, for example. Open Office accepts arrays as row_num/column_num, so the coercion is not needed and some formulas rely on this, but without it, these formulas are unlikely to work when files are open in Excel.
Regrettably, this type of coercion is not passed correctly to Open Office, and formula need to be "decoerced" to work, at least in my casual tests.
In order to use a formula that would work in both spreadsheet programs regarding shortening arrays, the only thing I have managed is the following (required: arrays must be single-column)
SUMPRODUCT(
(COLUMN(INDIRECT("R1C1:R"& ROWS(vals_to_mod) &"C"& ROWS(FREQUENCY(vals_for_freq,vals_for_freq)),FALSE))
-ROW(COLUMN(INDIRECT("R1C1:R"& ROWS(vals_to_mod) &"C"& ROWS(FREQUENCY(vals_for_freq,vals_for_freq)),FALSE))
=0)
*MOD(TRANSPOSE(FREQUENCY(vals_for_freq,vals_for_freq)),vals_to_mod)
)
(it "shortens" one array to the shortest of the pair, by creating an auxiliary array with TRUE/1s on the diagonal starting top-left and FALSE/0s elsewhere, therefore disregarding all defined values outside the square section of the array. Thus, SUMPRODUCT adds values within the diagonal of the square section which are the product of the corresponding values up to the last value of the shorter array.)