Is there a function alternative to get array/matrix/cell elements?

5 visualizaciones (últimos 30 días)
Dejia Kong
Dejia Kong el 17 de Dic. de 2019
Editada: fluid el 22 de Dic. de 2020
Usually we access array elements by using "()". For example, if a is an array, then we can use a(1) to get the first element of a.
However when a function returns an array and sometimes we only need some element/part of the result, we cannot use "()" to get what we want.
For example, if function fun returns a 5*1 array, and I only need the 3rd element of it, it is impossible to use
fun(para)(3)
to get what I want.
So my question is, is there a function alternative, to get part of the result array/matrix/cell like "()"/"{}" do.
Like I can use
somefun(fun(para),3)
to get what I want.
Obviously, it seems not hard to implement a function to achieve these with very few code. But I want to know if there are any built-in ones. Thanks.

Respuestas (3)

Guillaume
Guillaume el 17 de Dic. de 2019
Editada: Guillaume el 17 de Dic. de 2019
Indeed it would be very nice to be able to chain indexing to function calls. I believe it's an often requested enhancement but is non-trivial to implement.
The best way to go about this is indeed to write your own function. Certainly if you want clarity. There is indeed a built-in function that can do it, all indexing ( (), {} and . indexing) is actually implemented by subsref. It's not going to be very readable:
%to get fun(para)(3):
result = subsref(fun(para), struct('type', '()', 'subs', {{3}}))
You're better off using a temporary variable than this. Note that since matlab is copy-on-write there is neglible cost to a temporary variable, even if the content is large.
edit: There are also some undocumented ways, such as getfield:
%to get fun(para)(3):
getfield(fun(para), {3})
Use at your own peril, it may stop working or send the nuclear missiles launch code in a future version.
  4 comentarios
Dejia Kong
Dejia Kong el 18 de Dic. de 2019
Thanks! @fluids offers a question on stackoverflow which is similar to my question.
Some answers are similar to yours.
Adam Danz
Adam Danz el 18 de Dic. de 2019
@Dejia Kong, if you're going to use subsref() you should accept this answer since it's better than the one in stackoverflow. See Guillaume's comment above.
However, the cleanest and fastest and most readable solution (therefore the best solution) is to just use
result = fun(para);
result = result(3);

Iniciar sesión para comentar.


Adam Danz
Adam Danz el 17 de Dic. de 2019
Editada: Adam Danz el 17 de Dic. de 2019
Matlab does not have offer that syntax.
Here's a simple way to use a pair of anonymous functions to achive that.
% Define the pair of anonymous functions
% INPUTS to outputIdx()
% - fn: a function handle (example: @cumsum)
% - inputs: a cell array containing inputs to fn
% - idx: selected indices
% OUTPUT
% - a row vector same length as numel(idx) containing
% values from selected indices of the first ouput of fn function.
mgeti = @(m,i)m(i);
outputIdx = @(fn,inputs,idx)mgeti(fn(inputs{:}),idx);
Examples
% Get the 3rd index of cumsum(1:10);
outputIdx(@cumsum, {1:10}, 3)
% Get indices 3:5 of cumsum(magic(5),2)
outputIdx(@cumsum, {magic(5),2}, 3:5)
  2 comentarios
Adam Danz
Adam Danz el 17 de Dic. de 2019
Editada: Adam Danz el 17 de Dic. de 2019
For what it's worth, I timed all 3 suggestions 10000 times each (out of my own curiousity) using tic/toc on each iteration. Then I compared the median times.
% Inputs to all methods; not timed
x = 1:10000;
i = 3:10;
% The following is only for method 3
mgeti = @(m,i)m(i);
outputIdx = @(fn,inputs,idx)mgeti(fn(inputs{:}),idx);
% Method 1:
y = subsref(cumsum(x), struct('type', '()', 'subs', {{i}}));
% Method 2:
y = getfield(cumsum(x), {i});
% Method 3:
y = outputIdx(@cumsum, {x}, i);
From fastest to slowest (all were fast!): Methods [2,3,1]
  • Method 2 was ~1.2 times faster than method 3
  • Method 2 was ~2.2 times faster than method 1
  • Method 3 was ~2.0 times faster than method 1
As Guillaume mentioned, method 1 is more versatile/robust since it accepts a variety of indexing (method 2 probably does too, I didn't tinker with that). In terms of readability, my less-experienced opinion is that method 3 (anonymous functions) is fairly easy to read.
[update]
Method 4 is by far the fastest and cleanest. It is 1.75 times faster than method 2.
% method 4
y = cumsum(x);
y = y(3);
Dejia Kong
Dejia Kong el 18 de Dic. de 2019
Thanks! @fluids offers a question on stackoverflow which is similar to my question. Thank you for the answer!

Iniciar sesión para comentar.


fluid
fluid el 17 de Dic. de 2019
Editada: fluid el 22 de Dic. de 2020
  1 comentario
Dejia Kong
Dejia Kong el 18 de Dic. de 2019
Thank you very much, I searched many times, but I didn't find such a good question. Maybe because I was using the wrong key word TAT.

Iniciar sesión para comentar.

Categorías

Más información sobre Matrix Indexing en Help Center y File Exchange.

Productos

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by