3

For any function, I am able to dictate the variables to be returned by explicitly defining how many outputs I am expecting [out1,out2,...,outn] = ...

Edit: Being able to maximize potential # of outputs would also be useful

Example problem

The following code does exactly what is expected (yes, it is redundant with myArray(IND) = 1;)

[I,J] = ind2sub(size(myArray),IND)
myArray(I,J) = 1;

When I try to pass the function arguments directly, I don't get the results I wannt

myArray(ind2sub(size(myArray),IND)) = 1;

I effectively get myArray(I) = 1; when I wanted myArray(I,J) = 1;

Question

How can I dictate how many output variables are returned without explicitly defining my output arguments?

I expect some function in the eval() family or some typecasting [],{},(:), etc. will do the trick but I have not seen any documentation or gotten any of them to work.

Brendan Frick
  • 1,047
  • 6
  • 19

1 Answers1

5

The immediate issue with using the output of ind2sub directly as an index into myArray without an intermediate variable is that only the first output of ind2sub is requested by subsindex when indexing into myArray. The first output is then used as a linear index to index into myArray and assign values which resulting in your unexpected behavior.

Instead, you can use a cell array to capture as many outputs as you want and then rely on {} indexing to yield a comma-separated list.

[outputs{1:ndims(myArray)}] = ind2sub(size(myArray), IND);

You can then use this cell array containing all outputs to then forward all values as inputs or subscripts elsewhere:

myArray(outputs{:}) = 1;

That being said, in the example that you've shown, you really don't need to do any of this as you can use the linear indices IND to index into myArray directly. In fact, using the output of ind2sub will likely give you the incorrect assignment as every permutation of the subscripts will be used when assigning values rather than the element-wise pairing of subscripts.

myArray(IND) = 1;

In general, you can use this technique along with nargout to request all output arguments if there is a non-variable number of outputs.

[outputs{1:nargout('func')}] = func(inputs);
Community
  • 1
  • 1
Suever
  • 64,497
  • 14
  • 82
  • 101
  • Ah thank you, you've highlighted why there is a need for explicit output definitions for builtin functions with variable outputs. I was hoping for an in-line solution that allows explicit output definitions without variable assignment (i.e. `eval('foo(...),"nargout", 2')` ) but I have not seen any evidence that one exists – Brendan Frick Mar 31 '17 at 16:19
  • @BrendanFrick I'm confused. There is. it's `[outputs{1:2}] = thing` – Suever Mar 31 '17 at 16:21
  • Can you call that inline? `foo1([outputs{1:2}] = foo2(...))` – Brendan Frick Mar 31 '17 at 16:21
  • @BrendanFrick No you need the temporary variable. I see what you are referring to now – Suever Mar 31 '17 at 16:22
  • @BrendanFrick The better way to "chain" function calls like that would be to use a function handle to `foo2` and have `foo1` call that with the inputs and then use the explicit outputs internally – Suever Mar 31 '17 at 16:24
  • @BrendanFrick There is sometimes a wish to over "optimise" code by making everything inline, there is no real disadvantage to using two lines, if anything it increases readability. If you were insistent on 1 line you could always cheat with a semi-colon `[outputs{1:2}] = foo2(...); foo1(outputs{:})` – Wolfie Mar 31 '17 at 16:24
  • @Wolfie Not really an 'optimization' issue, more of a 'clean code' issue. In this instance the interior function is a very simple index mapping. The reason why I might prefer to use `eval('ind2sub(...),"nargout", 2') )` is because it is easier to recognize as _mapping a 1D index to a 2D index_ than multiple lines and a temporary variable. – Brendan Frick Mar 31 '17 at 16:37
  • 1
    @BrendanFrick Did you read my entire answer? The outputs that you're forwarding the way that you are aren't going to yield the correct result. See the linked post – Suever Mar 31 '17 at 16:39
  • @Suever Yes thank you! I edited the question (it is still redundant with just indexing 2D-array with a linear index) but it now should be doing what is described. My original intent was to map [1 2 3 4 5 6] to [1 2 3; 4 5 6] and I've done that in an easier way that is irrelevant to the original post – Brendan Frick Mar 31 '17 at 16:58