## How can I index a MATLAB array returned by a function without first assigning it to a local variable?

315

117

For example, if I want to read the middle value from `magic(5)`, I can do so like this:

``````M = magic(5);
value = M(3,3);
``````

to get `value == 13`. I'd like to be able to do something like one of these:

``````value = magic(5)(3,3);
value = (magic(5))(3,3);
``````

to dispense with the intermediate variable. However, MATLAB complains about `Unbalanced or unexpected parenthesis or bracket` on the first parenthesis before the `3`.

Is it possible to read values from an array/matrix without first assigning it to a variable?

2This syntax actually works fine in Octave. I only discovered this issue when my colleagues who use MATLAB were having issues running my code. – sffc – 2015-02-01T04:46:45.463

2

I also found the following article on this theme: http://www.mathworks.com/matlabcentral/newsreader/view_thread/280225 Anybody has new information on this theme, will it be implemented?

– None – 2011-05-17T23:19:21.867

1MATLAB in a nutshell. – user76284 – 2018-06-04T04:55:25.543

346

It actually is possible to do what you want, but you have to use the functional form of the indexing operator. When you perform an indexing operation using `()`, you are actually making a call to the `subsref` function. So, even though you can't do this:

``````value = magic(5)(3, 3);
``````

You can do this:

``````value = subsref(magic(5), struct('type', '()', 'subs', {{3, 3}}));
``````

Ugly, but possible. ;)

In general, you just have to change the indexing step to a function call so you don't have two sets of parentheses immediately following one another. Another way to do this would be to define your own anonymous function to do the subscripted indexing. For example:

``````subindex = @(A, r, c) A(r, c);     % An anonymous function for 2-D indexing
value = subindex(magic(5), 3, 3);  % Use the function to index the matrix
``````

However, when all is said and done the temporary local variable solution is much more readable, and definitely what I would suggest.

4@SamRoberts: true, but it does save you from the burden of calling `clear` on the temporary (which no-one ever does) -- the temporary tends to stick around longer – Rody Oldenhuis – 2013-06-28T11:33:27.787

1Wonderful! I stumbled around the internet for hours to find this! I'm going to stick with python. – vim – 2013-09-17T20:05:08.380

Hot damn. I didn't know this was possible. In the end, I'm still going to stick with the temp variable! – rayryeng – 2014-05-13T04:10:57.417

22well what do you know! though i agree it's pretty ugly, and probably less readable than a temp-var solution. +1 for impressive obscure matlab knowledge! – second – 2010-09-02T16:02:07.313

52That's disgusting, but a very clear answer. Good work! Should've guessed there'd be a back way into it. I'll think I'll carry on with the temp variable. – Joe Kearney – 2010-09-02T16:52:38.563

Any way to use this with `end`, as in `vectorReturningFunction()(1:end-1)`? – knedlsepp – 2015-02-21T12:03:49.293

1@knedlsepp: Unfortunately, I haven't been able to figure out a way to get `end` to work with the `subsref` syntax I used above. – gnovice – 2015-04-25T22:24:39.820

1

@knedlsepp - According to docs of `end`: "In that context, `end = (size(x,k))` when used as part of the kth index.". So I would say that the possibility of using `end` with `subsref` has a slight causality problem: because you're trying to find `size(x)` before `x` is known. However, "for the sake of freedom of shooting oneself in the foot", I suppose what you want is possible if you recursively do `subsref` (within the indexing term i.e. `subsref(...,{1:size(subsref(...))})`) and obtain the result so that you could know its size... :)

– Dev-iL – 2015-06-17T12:32:53.013

@Dev-iL: Would have been cool to have a feasible solution for this, but I think in the end I can still live without it. :-) – knedlsepp – 2015-06-17T12:37:58.933

@knedlsepp - I managed to do this using a crazily complicated command that relies on matlab's interface with python, and python's negative-indexing ability. Here goes: `vectorReturningFunction = @()1:10; endminus = 4; double(py.array.array('d',py.ast.literal_eval(wrap_system(['python -c "import sys; print eval(sys.argv[1])[0:-int(sys.argv[2])]" ' regexprep(char(py.array.array('d',reshape(vectorReturningFunction(),1,[])).tolist()), ' ', '') ' ' num2str(endminus)]))))`. where `wrap_system()` is: `function out = wrap_system(cmd); [~,out] = system(cmd);`. If you post a question I'll explain more.. – Dev-iL – 2015-06-17T14:37:55.987

(I know this is a year-old discussion, but...) Well, if you use the other possibility, creating a custom function (anonymous or not), you can convert any (-1, 0, inf,...) index to `end` inside the function... – BIOStheZerg – 2016-10-31T12:29:08.387

...nice answer! However, this is just another example (amongst many) showing that Matlab actually is an ugly bull*** language. – daniel451 – 2016-11-02T23:38:37.107

3This solution can be refined a tiny bit by using `substruct` like so: `subsref(magic(5), substruct('()', {3, 3}))`. – Edric – 2018-06-25T11:27:24.483

28Bear in mind that the intermediate variable is still fully created though. So if the purpose is to save memory by not having to create a temporary local variable, no luck. – Sam Roberts – 2011-09-21T16:18:00.953

Just out of curiosity - if you issue `[ subsref(A,substruct('{}',{':'})) ]`, it will not behave the same as `[ A{:} ]`...any ideas for a workaround there? – Rody Oldenhuis – 2018-09-18T23:16:50.203

1

@RodyOldenhuis: Using the functional form for indexing appears to also require you to specify the number of output arguments you want from the function, the default being one. The output from the operation is a comma-separated list, but only the first one is captured. Any attempt to capture multiple output arguments would not give you a simple way to concatenate them into a vector. It's all a moot point, however, since you could probably just use `cell2mat`: `cell2mat(A)`

– gnovice – 2018-09-19T03:41:17.353

7@SamRoberts: You can't really get around that in a strict-evaluation language like Matlab. The main reason people want this is conciseness/readability, not memory savings. – Mechanical snail – 2011-10-17T07:24:42.710

114

There was just good blog post on Loren on the Art of Matlab a couple days ago with a couple gems that might help. In particular, using helper functions like:

``````paren = @(x, varargin) x(varargin{:});
curly = @(x, varargin) x{varargin{:}};
``````

where `paren()` can be used like

``````paren(magic(5), 3, 3);
``````

would return

``````ans = 16
``````

I would also surmise that this will be faster than gnovice's answer, but I haven't checked (Use the profiler!!!). That being said, you also have to include these function definitions somewhere. I personally have made them independent functions in my path, because they are super useful.

These functions and others are now available in the Functional Programming Constructs add-on which is available through the MATLAB Add-On Explorer or on the File Exchange.

2This is a slightly more general version of the second half of gnovice's answer; also good. – Joe Kearney – 2013-02-28T17:23:38.387

What about `myfunc().attr`? – gerrit – 2013-03-19T15:22:35.990

@gerrit, how does at help? and the x.attr() field isn't available unless you have the database toolbox. – T. Furfaro – 2013-03-21T16:14:43.497

@T.Furfaro Huh? If `myfunc()` returns a structure that includes an attribute `attr`, then to access `attr` currently I need to do `S = myfunc(); S.attr`. The question is if we can have a helper function like `getattr(myfunc(), 'attr')` in analogy to the `paren` and `curly` helpers. I don't understand what this has to do with the database toolbox. – gerrit – 2013-03-21T16:27:14.370

1

@gerrit Sorry, total confusion ( I wasn't aware that your "attr" was arbitrary -- in the db tb there's such a field explicity defined ). I believe what you're looking for is getfield()

– T. Furfaro – 2013-04-04T14:57:20.207

I've edited in a link to the add-on containing a range of these functions, which is available through the MATLAB add-on explorer or the file exchange. – nekomatic – 2016-12-22T11:45:26.647

74

How do you feel about using undocumented features:

``````>> builtin('_paren', magic(5), 3, 3)               %# M(3,3)
ans =
13
``````

or for cell arrays:

``````>> builtin('_brace', num2cell(magic(5)), 3, 3)     %# C{3,3}
ans =
13
``````

Just like magic :)

## UPDATE:

Bad news, the above hack doesn't work anymore in R2015b! That's fine, it was undocumented functionality and we cannot rely on it as a supported feature :)

For those wondering where to find this type of thing, look in the folder `fullfile(matlabroot,'bin','registry')`. There's a bunch of XML files there that list all kinds of goodies. Be warned that calling some of these functions directly can easily crash your MATLAB session.

@RodyOldenhuis: I dont recall now, I guess I must have read it in some buried code ;) – Amro – 2013-06-28T15:15:37.550

2The colon (:) operator must be used with apostrophes `':'` to avoid the error `Undefined function or variable "builtin"`. – Dominik – 2014-11-20T18:19:07.983

@Dominik: right, say you want to slice the 2nd column, that would be: `builtin('_paren', magic(5), ':', 2)` (in certain places it does work without the quotations directly as `:` as opposed to `':'`, like when running in the command prompt directly not from inside a function. I guess that's a bug in the parser!) – Amro – 2014-11-20T18:54:59.643

2I don't suppose there is some way to use `end` with this? – knedlsepp – 2015-02-21T12:07:41.063

2

@knedlsepp: No, unfortunately the whole `end`-trickery doesn't work in this syntax, you'll have to be explicit in your indexing.. (Same limitation applies for most other listed answers)

– Amro – 2015-02-21T13:45:51.320

49

At least in MATLAB 2013a you can use `getfield` like:

``````a=rand(5);
getfield(a,{1,2}) % etc
``````

to get the element at (1,2)

5This is actually a nice method. Any drawbacks? – mmumboss – 2014-03-07T16:28:07.963

6@mmumboss: That's undocumented behaviour, this functionality may disappear without notice in future versions. Besides this no disadvantages. – Daniel – 2015-03-22T08:55:12.780

3As of MATLAB2017b, this functionality is documented. – njspeer – 2018-04-08T03:48:08.390

15

unfortunately syntax like `magic(5)(3,3)` is not supported by matlab. you need to use temporary intermediate variables. you can free up the memory after use, e.g.

``````tmp = magic(3);
myVar = tmp(3,3);
clear tmp
``````

2Is there anywhere we can vote for this feature to be added? – Evgeni Sergeev – 2012-12-18T01:58:41.767

6@EvgeniSergeev you can vote with your feet, by using a language such as R which supports this. – jwg – 2012-12-20T06:43:11.060

12

Note that if you compare running times with the standard way (asign the result and then access entries), they are exactly the same.

``````[email protected](M,i,j) M(i,j);
>> for nit=1:10;tic;subs(magic(100),1:10,1:10);tlap(nit)=toc;end;mean(tlap)

ans =

0.0103

>> for nit=1:10,tic;M=magic(100); M(1:10,1:10);tlap(nit)=toc;end;mean(tlap)

ans =

0.0101
``````

To my opinion, the bottom line is : MATLAB does not have pointers, you have to live with it.

6

It could be more simple if you make a new function:

``````function [ element ] = getElem( matrix, index1, index2 )
element = matrix(index1, index2);
end
``````

and then use it:

``````value = getElem(magic(5), 3, 3);
``````

but this is exactly what `subref` does... but in a more general way. – Shai – 2013-05-01T16:58:49.880

2yes, more general way, but not friendly... to much ugly in my opinion. – Vugar – 2013-05-01T17:03:36.627

4

Your initial notation is the most concise way to do this:

``````M = magic(5);  %create
value = M(3,3);  % extract useful data
clear M;  %free memory
``````

If you are doing this in a loop you can just reassign M every time and ignore the clear statement as well.

5I agree that this is more concise, and clearing is a good idea in a loop, as you say, but the question was specifically whether the intermediate assignment can be avoided. – Joe Kearney – 2012-08-21T08:43:42.017

1

To complement Amro's answer, you can use `feval` instead of `builtin`. There is no difference, really, unless you try to overload the operator function:

BUILTIN(...) is the same as FEVAL(...) except that it will call the original built-in version of the function even if an overloaded one exists (for this to work, you must never overload BUILTIN).

``````>> feval('_paren', magic(5), 3, 3)               % M(3,3)
ans =
13

>> feval('_brace', num2cell(magic(5)), 3, 3)     % C{3,3}
ans =
13
``````

What's interesting is that `feval` seems to be just a tiny bit quicker than `builtin` (by ~3.5%), at least in Matlab 2013b, which is weird given that `feval` needs to check if the function is overloaded, unlike `builtin`:

``````>> tic; for i=1:1e6, feval('_paren', magic(5), 3, 3); end; toc;
Elapsed time is 49.904117 seconds.
>> tic; for i=1:1e6, builtin('_paren', magic(5), 3, 3); end; toc;
Elapsed time is 51.485339 seconds.
``````